[Java]-同步工具类CountDownLatch与CyclicBarrier简介

CountDownLatch与CyclicBarrier是在java1.5被引入的线程同步工具类。

CountDownLatch

CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(不能用作互斥)。可用于:

  • 让多个线程等待:模拟并发,让并发线程一起执行。初始化一个共享的CountDownLatch(1),多个线程在开始执行任务前先countdownlatch.await()等待,当主线程调用countDown()时,计数器变为0,多个线程同时被唤醒。
  • 让单个线程等待:某一线程在开始运行前等待n个线程执行完毕。初始化一个 CountDownLatch(n),每当一个任务线程执行完毕,就调用countdownLatch.countDown()将计数器减1 ,当计数器的值变为0时,在CountDownLatch上await()的线程就会被唤醒。

CountDownLatch是一次性的,其值只能在构造方法中初始化,当CountDownLatch使用完毕后,它不能再次被使用。

主要方法说明

public void countDown():递减计数,当计数到达零,则释放所有等待的线程。

public boolean await(long timeout,TimeUnit unit)await():等待计数器:

  • 计数到达零,则该方法返回true值;
  • 超出了指定的等待时间,则返回值为false;如果该时间小于等于零,则该方法根本不会等待。

等待其他线程完成示例

构造与等待线程数量相等的计数器,并在每个线程执行完成后调用countDown:

CountDownLatch countLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {
    int index = i;
    new Thread(() -> {
        try {
            Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(100));
            System.out.println(index + "-thread finished");
            countLatch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
}

countLatch.await();     // 阻塞,当计数器==0,就唤醒主线程往下执行。
System.out.println("main thread finished");

// 3-thread finished
// 4-thread finished
// 0-thread finished
// 1-thread finished
// 2-thread finished
// main thread finished

等待信号一起执行示例

初始化值为1的计数器,然后等待线程中通过await等待;主线程在合适的时候通过countDown来触发信号,让所有等待线程开始运行:

CountDownLatch countLatch = new CountDownLatch(1);
for (int i = 0; i < 5; i++) {
    int index = i;
    new Thread(() -> {
        try {
            // ready, wait for main-signal
            countLatch.await();
            System.out.println(index + "-thread to run");
            Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(100));
            System.out.println(index + "-thread finished");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
}

Thread.sleep(1000);
System.out.println("main thread send signal");
countLatch.countDown();

Thread.sleep(2000);

// main thread send signal
// 0-thread to run
// 2-thread to run
// 3-thread to run
// 1-thread to run
// 4-thread to run
//  
// 1-thread finished
// 2-thread finished
// 4-thread finished
// 0-thread finished
// 3-thread finished

CyclicBarrier

在CyclicBarrier类的内部有一个计数器,每个线程在到达屏障点的时候都会调用await方法将自己阻塞,此时计数器会减1,当计数器减为0的时候所有因调用await方法而被阻塞的线程将被唤醒。

主要方法说明

public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
    
public int await()
public int await(long timeout, TimeUnit unit) 
  • parties 是参与线程的个数;
  • Runnable 参数,表示最后一个到达的线程要做的任务;

示例

初始化与线程数量相等的Barrier,然后在每个线程进入后await:

CyclicBarrier barrier = new CyclicBarrier(5, new Runnable() {
    @Override
    public void run() {
        System.out.println("The last thread arrived barrier: " + Thread.currentThread().getName());
    }
});

for (int i = 0; i < 5; i++) {
    int index = i;
    new Thread(() -> {
        try {
            Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(100));
            System.out.println(index + "-thread come to barrier");
            barrier.await();
            System.out.println(index + "-thread to run");
            Thread.sleep(1000 + ThreadLocalRandom.current().nextInt(100));
            System.out.println(index + "-thread finished");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }).start();
}

Thread.sleep(3000);

// 3-thread come to barrier
// 2-thread come to barrier
// 1-thread come to barrier
// 0-thread come to barrier
// 4-thread come to barrier
// The last thread arrived barrier: Thread-4
// 
// 4-thread to run
// 0-thread to run
// 1-thread to run
// 2-thread to run
// 3-thread to run
// 
// 0-thread finished
// 3-thread finished
// 1-thread finished
// 4-thread finished
// 2-thread finished
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值