java CyclicBarrier以及和CountDownLatch的区别
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。
CountDownLatch是一个同步的辅助类,允许一个或多个线程,等待其他一组线程完成操作,再继续执行。
CyclicBarrier是一个同步的辅助类,允许一组线程相互之间等待,达到一个共同点,再继续执行。
区别:CountDownLatch调用countDown()不能让线程在内部等待,也就是不能线程内部阻塞。而CyclicBarrier在调用await()方法时立刻阻塞等待其他全部的线程调用await()。
举例:
//CyclicBarrier 举例
package com.hts;
import java.util.concurrent.*;
public class CyclicBarrierTest {
class Task1 implements Runnable{
CyclicBarrier cyclicBarrier;
Task1(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("任务1开始了");
try {
System.out.println("任务1等待其他任务开始");
cyclicBarrier.await();
System.out.println("任务1执行完");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class Task2 implements Runnable{
CyclicBarrier cyclicBarrier;
Task2(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("任务2开始了");
try {
System.out.println("任务2等待其他任务开始");
cyclicBarrier.await();
System.out.println("任务2执行完");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
class Task3 implements Runnable{
CyclicBarrier cyclicBarrier;
Task3(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("任务3开始了");
try {
System.out.println("任务3等待其他任务开始");
cyclicBarrier.await();
System.out.println("任务3执行完");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(3);
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new CyclicBarrierTest().new Task1(cyclicBarrier));
executorService.submit(new CyclicBarrierTest().new Task2(cyclicBarrier));
executorService.submit(new CyclicBarrierTest().new Task3(cyclicBarrier));
}
}
执行结果:
可以看出,在线程内部一定会等待每个线程都开始了才会,全部的线程才会输出“执行完”,由此可以得出结论:所有线程在互相等待。再看看CountDownLatch例子
package com.hts;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CountDownLatchTest {
class Task1 implements Runnable{
CountDownLatch countDownLatch;
Task1(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("任务1开始了");
System.out.println("任务1等待其他任务开始");
countDownLatch.countDown();
System.out.println("任务1执行完");
}
}
class Task2 implements Runnable{
CountDownLatch countDownLatch;
Task2(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("任务2开始了");
System.out.println("任务2等待其他任务开始");
countDownLatch.countDown();
System.out.println("任务2执行完");
}
}
class Task3 implements Runnable{
CountDownLatch countDownLatch;
Task3(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("任务3开始了");
System.out.println("任务3等待其他任务开始");
countDownLatch.countDown();
System.out.println("任务3执行完");
}
}
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(3);
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new CountDownLatchTest().new Task1(countDownLatch));
executorService.submit(new CountDownLatchTest().new Task2(countDownLatch));
executorService.submit(new CountDownLatchTest().new Task3(countDownLatch));
}
}
执行结果:
可以看出,CountDownLatch不会互相等待,只会观察计数器是否到0,然后让处于await的线程执行。当然有些情况还是有通用情况,比如你在使用CyclicBarrier 时,在每个任务线程执行结束后调用await方法可以做到CountDownLatch的效果。当然CountDownLatch可以做到让某个线程等待其他线程执行到某个地方的时候就开始执行,比如主线程只需要等待其他线程任务执行一半的时候就开始执行等等。
总体来说,CountDownLatch观察计数器是否0,只有调用await的线程阻塞。CyclicBarrier 则是调用await()则开始阻塞,直到全部的线程都调用await()后开始执行。