文章目录
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是可以重用的。(本文没有对这一点进行总结,读者有兴趣可以自己实验)