[并发控制]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不行

目录
相关文章
|
7月前
|
Java 测试技术
CountDownLatch、CyclicBarrier让线程听我号令
CountDownLatch、CyclicBarrier让线程听我号令
82 0
|
7月前
CountDownLatch和CyclicBarrier你使用过吗?
CountDownLatch和CyclicBarrier你使用过吗?
45 0
|
4月前
|
Java
CountDownLatch、CyclicBarrier 使用区别
CountDownLatch、CyclicBarrier 使用区别
37 1
CountDownLatch和CyclicBarrier的区别
CountDownLatch和CyclicBarrier的区别
41 0
|
JavaScript 小程序 Java
JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理 上
JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理 上
|
消息中间件 JavaScript 小程序
JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理 下
JUC多线程:CountDownLatch、CyclicBarrier、Semaphore 同步器原理 下
并发编程之倒计锁 CountDownLatch
上文我们知道了 `Semaphore` 信号量的用法,那么这一篇基本不用学了。因为原理基本上是一样的。 但是用法不太一样。`Semaphore` 是获取到资源就执行,获取不到资源就等待。 `CountDownLatch` 跟 `Semaphore` 正好相反。
148 0
JUC并发编程——CountDownLatch&Semaphore&CyclicBarrier
JUC并发编程——CountDownLatch&Semaphore&CyclicBarrier
157 0
JUC并发编程——CountDownLatch&Semaphore&CyclicBarrier
|
安全
JUC CyclicBarrier和Semphore
JUC CyclicBarrier和Semphore
107 0