Java并发编程之CountDownLatch & CyclicBarrier

CountDownLatch

概述

CountDownLatch类位于java.util.concurrent包下,利用它可以实现线程间同步等功能。
例如,现在有一个主线程和两个子线程,主线程需要等待两个子线程执行结束之后才能执行,那么就可以通过CountDownLatch来实现。

构造器 & 方法

构造器

CountDownLatch只提供了一个构造器

public CountDownLatch(int count) {
	if (count < 0) throw new IllegalArgumentException("count < 0");
	this.sync = new Sync(count);
}

其中count指的是需要等待子线程执行的个数。例如count为2时,指的是主线程需要等待两个子线程执行结束,才能够继续执行主线程。

方法

CountDownLatch主要有以下几个重要方法

public void await() throws InterruptedException { };
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
public void countDown() { }; 
  • await()方法 : 主线程调用await()方法,当子线程未完全执行结束时,主线程阻塞在此处。
  • await(long timeout, TimeUnit unit) : 主线程调用await(long timeout, TimeUnit unit)方法,当子线程未完全执行结束时,主线程阻塞在此处。当等待了timeout时间之后,子线程还是没有执行结束,则主线程也不再继续阻塞,而是继续往下执行。
  • countDown() : 子线程调用countDown(),当子线程执行结束之后,调用这个方法,类似于计数器减一的操作,当CountDownLatch值变为0的时候,主线程可以继续往下执行。

例子

此处,我们模拟一个主线程等待两个子线程的例子:

代码

public class CountDownLatchDemo {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(2);
        new Thread() {
            @Override
            public void run() {
                System.out.println("子线程1 运行");
                System.out.println("子线程1 结束");
                try {
                    Thread.sleep(3000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                System.out.println("子线程2 运行");
                System.out.println("子线程2 结束");
                try {
                    Thread.sleep(3000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                countDownLatch.countDown();
            }
        }.start();
        System.out.println("主线程等待子线程结束");
        try {
            countDownLatch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("主线程 运行");
        System.out.println("主线程 结束");
    }
}

运行结果

子线程1 运行
子线程1 结束
子线程2 运行
子线程2 结束
主线程等待子线程结束
主线程 运行
主线程 结束

CyclicBarrier

概述

CyclicBarrier类位于java.util.concurrent包下,利用它可以实现线程间共同等待某个状态,当等到这个状态时,线程可以继续往下执行,当没有达到这个状态时,所有线程阻塞。
例如,现在有一组线程1,2,3,4,它们共享同一个cyclicBarrier实例,只有当所有线程全部调用了cyclicBarrier的await()方法之后,这些线程才能够继续执行cyclicBarrier.await()之后的代码。

构造器 & 方法

构造器

CyclicBarrier提供了二个构造器

public CyclicBarrier(int parties, Runnable barrierAction) {
}
public CyclicBarrier(int parties) {
}

其中parties指的是需要parties个线程等待CyclicBarrier的状态。barrierAction指的是CyclicBarrier达到状态之后执行的任务。

方法

CyclicBarrier主要有以下几个重要方法

public int await() throws InterruptedException, BrokenBarrierException {};
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException {};
  • await()方法 : 线程组内所有需要等待CyclicBarrier的线程都需要调用await()方法,当线程调用await()后,线程阻塞在此处,直到所有线程均调用了await()方法。
  • await(long timeout, TimeUnit unit) : 线程组内所有需要等待CyclicBarrier的线程都需要调用await()方法,当线程调用await()后,线程阻塞在此处,直到所有线程均调用了await()方法。当某一部分线程等待了timeout时间后,还是未等到CyclicBarrier达到所需的状态,则抛出异常,这部分线程继续往下执行

例子1

此处,我们模拟一组线程等待某个状态的例子:

代码

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
        new Thread() {
            @Override
            public void run() {
                System.out.println("线程1 执行");
                try {
                    Thread.sleep(5000);
                    System.out.println("线程1 中途完成");
                    cyclicBarrier.await();
                    System.out.println("线程1 继续执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }catch(BrokenBarrierException e){
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                System.out.println("线程2 执行");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程2 中途完成");
                    cyclicBarrier.await();
                    System.out.println("线程2 继续执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }catch(BrokenBarrierException e){
                    e.printStackTrace();
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                System.out.println("线程3 执行");
                try {
                    Thread.sleep(2000);
                    System.out.println("线程3 中途完成");
                    cyclicBarrier.await();
                    System.out.println("线程3 继续执行");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }catch(BrokenBarrierException e){
                    e.printStackTrace();
                }
            }
        }.start();

    }
}

运行结果

线程1 执行
线程2 执行
线程3 执行
线程2 中途完成
线程3 中途完成
线程1 中途完成
线程1 继续执行
线程2 继续执行
线程3 继续执行

例子2

此处,我们模拟一组线程等待某个状态,当等到这个状态,执行预先设定好的任务:

代码

public class CyclicBarrierDemo1 {
    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3,new Runnable() {
            @Override
            public void run() {
                System.out.println("当前线程" + Thread.currentThread().getName() + "继续执行");
            }
        });
        new Thread() {
            @Override
            public void run() {
                System.out.println("线程1 执行");
                try {
                    Thread.sleep(5000);
                    System.out.println("线程1 中途完成");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }catch(BrokenBarrierException e){
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                System.out.println("线程2 执行");
                try {
                    Thread.sleep(1000);
                    System.out.println("线程2 中途完成");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }catch(BrokenBarrierException e){
                    e.printStackTrace();
                }
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                System.out.println("线程3 执行");
                try {
                    Thread.sleep(6000);
                    System.out.println("线程3 中途完成");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }catch(BrokenBarrierException e){
                    e.printStackTrace();
                }
            }
        }.start();
    }
}

运行结果

线程1 执行
线程2 执行
线程3 执行
线程2 中途完成
线程1 中途完成
线程3 中途完成
当前线程Thread-2继续执行

当三个线程都到达barrier状态后,会从三个线程中选择一个线程去执行Runnable任务。
具体是怎么选的呢,经过测试发现,哪一个线程最后调用的cyclicBarrier.await()方法,则选取哪个线程执行Runnable方法。

总结

相同点

  • CountDownLatch和CyclicBarrier都能够实现线程之间的等待

不同点

  • CountDownLatch一般用于某个线程等待若干其他线程执行完毕(此处的“某个线程”不属于“若干个其他线程”)
  • CyclicBarrier一般用于一组线程互相等待至某个状态,相当于这组线程等待它们自身达到某个状态,而不是其他线程组达到某个状态。
  • CountDownLatch是不能重用的,而CyclicBarrier是可以重用的。(本文没有对这一点进行总结,读者有兴趣可以自己实验)
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值