1. 闭锁
闭锁是 J.U.C包下的一个同步组件。
作用:
被等待线程调用countdown方法计数器减1,减到0时等待线程(调用await方法的线程)被唤醒。
- 闭锁场景下,一个或者多个线程等待其他线程准备好了才被唤醒。
一个闭锁工作起来就像一道大门:直到闭锁达到终点状态之前,门一直是关闭的,没有线程通过,在终点状态到来的时候,门开了,允许所有线程都通过。一旦闭锁到达了终点状态,他就不能够在改变状态了,所以它会永远保持敞开的状态。
适用场景
1.确保一个计算不会执行,直到它需要的资源被初始化。
2.确保一个服务不会开始,直到它依赖的服务都已经开始。
3.等待直到活动的所有部分都为继续处理做好准备。比如王者荣耀需要等待所有玩家准备才能开始。
代码实例
public class CountDownLatchExample1 {
private final static int threadCount = 200;
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newCachedThreadPool();
final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadNum = i;
exec.execute(() -> {
try {
test(threadNum);
} catch (Exception e) {
log.error("exception", e);
} finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await();
log.info("finish");
exec.shutdown();
}
private static void test(int threadNum) throws Exception {
Thread.sleep(100);
log.info("{}", threadNum);
Thread.sleep(100);
}
}
2. 栅栏
CyclicBarrier 字面意思是回环栅栏,回环的意思是它能够被重复利用,当然前提是在所有线程释放了以后。
作用
栅栏描述的是线程间的相互等待,相互等待的线程都准备好就可以继续下去了。而且栅栏的计数器可以重置,这样意味着其中有线程准备过程执行失败可以全部重新准备。
比较
能否复用 | 场景 | |
---|---|---|
CountDownLatch | 计数器不能重置 | 一个或者多个线程等待其他线程执行完成 |
CyclicBarrier | 计数器可以重置 | 一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行 |
代码实例
public class CyclicBarrierExample1 {
private static CyclicBarrier barrier = new CyclicBarrier(5);
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newCachedThreadPool();
// 十个线程
for (int i = 0; i < 10; i++) {
final int threadNum = i;
Thread.sleep(1000);
executor.execute(() -> {
try {
race(Thread.currentThread().getName());
} catch (Exception e) {
System.out.println("exception "+ e);
}
});
}
executor.shutdown();
}
private static void race(String threadNum) throws Exception {
Thread.sleep(1000);
System.out.printf("%s is ready \n", threadNum);
barrier.await();
System.out.printf("%s continue \n", threadNum);
}
}
参考链接:
https://www.jianshu.com/p/79f95bb81c67
https://www.jianshu.com/p/5812bb54c44f