开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第42天,点击查看活动详情
概述
CyclicBarrier和CountdownLatch的作用类似,但是CountdownLatch的缺点在于不能重用,见下:
private static void test1() {
ExecutorService service = Executors.newFixedThreadPool(5);
for (int i = 0; i < 3; i++) {
CountDownLatch latch = new CountDownLatch(2);
service.submit(() -> {
log.debug("task1 start...");
sleep(1);
latch.countDown();
});
service.submit(() -> {
log.debug("task2 start...");
sleep(2);
latch.countDown();
});
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("task1 task2 finish...");
}
service.shutdown();
}
想要重复使用CountdownLatch进行同步,必须创建多个CountDownLatch对象。
[ˈsaɪklɪk ˈbæriɚ] 循环栅栏,用来进行线程协作,等待线程满足某个计数。构造时设置『计数个数』,每个线程执 行到某个需要“同步”的时刻调用 await() 方法进行等待,当等待的线程数满足『计数个数』时,继续执行。
CyclicBarrier cb = new CyclicBarrier(2); // 个数为2时才会继续执行
new Thread(()->{
System.out.println("线程1开始.."+new Date());
try {
cb.await(); // 当个数不足时,等待
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程1继续向下运行..."+new Date());
}).start();
new Thread(()->{
System.out.println("线程2开始.."+new Date());
try { Thread.sleep(2000); } catch (InterruptedException e) { }
try {
cb.await(); // 2 秒后,线程个数够2,继续运行
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("线程2继续向下运行..."+new Date());
}).start();
注意
CyclicBarrier 与 CountDownLatch 的主要区别在于 CyclicBarrier 是可以重用的 >CyclicBarrier 可以被比 喻为『人满发车』
CountDownLatch的计数和阻塞方法是分开的两个方法,而CyclicBarrier是一个方法。
CyclicBarrier的构造器还有一个Runnable类型的参数,在计数为0时会执行其中的run方法。
线程安全集合类概述
线程安全集合类可以分为三大类:
-
遗留的线程安全集合如
Hashtable,Vector -
使用
Collections装饰的线程安全集合,如:-
Collections.synchronizedCollection -
Collections.synchronizedList -
Collections.synchronizedMap -
Collections.synchronizedSet -
Collections.synchronizedNavigableMap -
Collections.synchronizedNavigableSet -
Collections.synchronizedSortedMap -
Collections.synchronizedSortedSet -
说明:以上集合均采用修饰模式设计,将非线程安全的集合包装后,在调用方法时包裹了一层synchronized代码块。其并发性并不比遗留的安全集合好。
-
-
java.util.concurrent.*
重点介绍java.util.concurrent.* 下的线程安全集合类,可以发现它们有规律,里面包含三类关键词: Blocking、CopyOnWrite、Concurrent
-
Blocking 大部分实现基于锁,并提供用来阻塞的方法
-
CopyOnWrite 之类容器修改开销相对较重
-
Concurrent 类型的容器
-
内部很多操作使用 cas 优化,一般可以提供较高吞吐量
-
弱一致性
-
遍历时弱一致性,例如,当利用迭代器遍历时,如果容器发生修改,迭代器仍然可以继续进行遍 历,这时内容是旧的
-
求大小弱一致性,size 操作未必是 100% 准确
-
读取弱一致性
-
-
遍历时如果发生了修改,对于非安全容器来讲,使用 fail-fast 机制也就是让遍历立刻失败,抛出 ConcurrentModificationException,不再继续遍历