[并发控制]CountDownLatch和CyclicBarrier

简介: [并发控制]CountDownLatch和CyclicBarrier

等待唤醒机制

在java.util.concurrent包下 有许多并发工具来帮我们以简单的方式实现多线程的各种机制

今天我们来看CountDownLatch和CyclicBarrier,他们都能实现使线程间等待和唤醒机制。

CountDownLanch

先来看CountDownLatch,它最主要的方法是countDown(),和await()方法。CountDownLatch允许定义一个数量 表示要等待的线程数。假如有这么一个情景,某个线程需要等待执行某些任务的5个线程执行完毕后在执行。此时可以使用CountDownLatch的构造器传入需要等待的线程数。

 final CountDownLatch latch = new CountDownLatch(5);

然后启动五个线程

 for (int i = 0; i < 5; i++) {
    Thread th = new Thread(new Task(latch ));
    th.start();
 }

在每个线程执行完任务后调用latch.countDown()

需要等待的线程需要调用lanch.await(),然后将需要等待的线程和五个线程同时启动你会看到,5个线程是先执行的

实例:

package thread;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
 * 假设有三个同学 老师必须等到三个同学都完成作业才开始检查
 */
public class CountDownLanchTest {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        final CountDownLatch latch = new CountDownLatch(3);
        Student s1 = new Student(latch);
        Student s2 = new Student(latch);
        Student s3 = new Student(latch);
        Thread teacher = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    latch.await();
                } catch (InterruptedException interruptedException) {
                    interruptedException.printStackTrace();
                }
                System.out.println("老师检查");
            }
        });
        executorService.execute(teacher);
        executorService.execute(s1);
        executorService.execute(s2);
        executorService.execute(s3);
        executorService.shutdown();
    }
}
class Student implements Runnable {
    private CountDownLatch latch;
    public Student(CountDownLatch latch) {
        this.latch = latch;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+ " begin do home work");
        try {
            //模拟做作业时间
            TimeUnit.MILLISECONDS.sleep(3000);
        } catch (InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "已完成");
        //完成作业 执行
        latch.countDown();
    }
}

执行结果:

pool-1-thread-2 begin do home work

pool-1-thread-4 begin do home work

pool-1-thread-3 begin do home work

pool-1-thread-2已完成

pool-1-thread-3已完成

pool-1-thread-4已完成

老师检查

CyclicBarrier

再说cyclicBarrier,其实他们俩有一点相似,CountDownLatch实现的是等待某一部分任务执行完毕,最后执行等待的任务。不同的是cyclicBarrier实现需要执行任务的一组线程相互等待,直至这些线程均已就绪才开始执行任务。发现了吗 前者是等待任务执行完毕,才执行等待任务,后者是等待执行任务的线程全部就绪,才一起开始执行任务。此外这个cyclicBarrier是可以重置的,本篇暂时不详细解释。并且cyclicBarrier的构造方法可以传入一个线程,此线程会在其它任务线程均已就绪后执行。

来看示例:

package thread;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
/**
 * 线程间相互等待 cyclicBarrier可复用
 * 类似跑步比赛 各位选手全部就位后 裁判才会打响发令枪
 */
public class CycleBarrierTest {
    public static void main(String[] args) {
    //定义需要等待的线程数,以及所有线程就绪后执行的任务
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
            @Override
            public void run() {
                System.out.println("5个线程就位");
            }
        });
        for (int i = 0; i < 5; i++) {
            Thread th = new Thread(new Task(cyclicBarrier));
            th.start();
        }
    }
}
class Task implements Runnable{
    private CyclicBarrier cyclicBarrier;
    public Task(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 已就位");
        try {
            cyclicBarrier.await();
        } catch (InterruptedException interruptedException) {
            interruptedException.printStackTrace();
        } catch (BrokenBarrierException e) {
           //e.printStackTrace();
            System.out.println(cyclicBarrier.isBroken());
        }
        //任务
        System.out.println(Thread.currentThread().getName() + " is running");
    }
}

执行结果:

Thread-0 已就位

Thread-4 已就位

Thread-2 已就位

Thread-1 已就位

Thread-3 已就位

5个线程就位

Thread-2 is running

Thread-4 is running

Thread-0 is running

Thread-3 is running

Thread-1 is running

假如理解了上面两个简单的例子,对这个两个类的使用应该就有一些谱了,其实看那么多概念不如马上动手实践一下,能更好的理解

总结:

CountLanch和CycleBarrier都可以实现线程等待,CountLanch 一般用于一个线程等待其它线程执行完毕,CycleBarrier用于一组线程等待至某个状态后一起执行;CycleBarrier可以重复使用CountLanch不行

目录
相关文章
|
6天前
|
Java 测试技术
CountDownLatch、CyclicBarrier让线程听我号令
CountDownLatch、CyclicBarrier让线程听我号令
45 0
|
8月前
|
Java BI
CountDownLatch,CyclicBarrier,Semaphore
在开发过程中我们常常遇到需要对多个任务进行汇总,比如报表,或者大屏显示,需要将所有接口的数据都 获取到后再进行汇总,如果使用同步的方式,那么会比较耗时,体验不好,所以我们使用多线程,但是使用多线程 只能异步的执行,有些接口响应比较快,有些比较慢,而返回结果之间又有依赖,这样就无法汇总了, 所以我们引入了CountDownLatch,它能让所有子线程全部执行完毕后主线程才会往下执行,如果子线程没有执行完毕 ,那么主线程将无法继续向下执行。
40 0
|
6天前
|
Java
JUC 常用 4 大并发工具类 CountDownLatch、CyclicBarrier、Semaphore、ExChanger
JUC 常用 4 大并发工具类 CountDownLatch、CyclicBarrier、Semaphore、ExChanger
|
6月前
CountDownLatch和CyclicBarrier的区别
CountDownLatch和CyclicBarrier的区别
22 0
|
JavaScript 小程序 Java
JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理 上
JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理 上
|
消息中间件 JavaScript 小程序
JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理 下
JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理 下
JUC并发编程——CountDownLatch&Semaphore&CyclicBarrier
JUC并发编程——CountDownLatch&Semaphore&CyclicBarrier
123 0
JUC并发编程——CountDownLatch&Semaphore&CyclicBarrier
CountDownLatch&CyclicBarrier&Semaphore
本文将介绍一下CountDownLatch 、 CyclicBarrier 、 Semaphore这几个控制线程的类。
 CountDownLatch&CyclicBarrier&Semaphore