Semaphore 是什么?
Semaphore ,是一种新的同步类,它是一个计数信号。从概念上讲,从概念上讲,信号量维护了一个许可集合。
- 如有必要,在许可可用前会阻塞每一个
#acquire()
方法,然后再获取该许可。 - 每个
#release()
方法,添加一个许可,从而可能释放一个正在阻塞的获取者。 - 但是,不使用实际的许可对象,Semaphore 只对可用许可的数量进行计数,并采取相应的行动。
信号量常常用于多线程的代码中,比如数据库连接池。
- 使用方式,可以看看 《JAVA多线程 – 信号量(Semaphore)》 。
- 源码解析,可以看看 《【死磕 Java 并发】—– J.U.C 之并发工具类:Semaphore》 。
说说 CountDownLatch 原理
CountDownLatch ,字面意思是减小计数(CountDown)的门闩(Latch)。它要做的事情是,等待指定数量的计数被减少,意味着门闩被打开,然后进行执行。
CountDownLatch 默认的构造方法是 CountDownLatch(int count)
,其参数表示需要减少的计数,主线程调用 #await()
方法告诉 CountDownLatch 阻塞等待指定数量的计数被减少,然后其它线程调用 CountDownLatch 的 #countDown()
方法,减小计数(不会阻塞)。等待计数被减少到零,主线程结束阻塞等待,继续往下执行。
- CountDownLatch 的使用示例,请看 《Java 多线程 CountDownLatch 用法》 。
- CountDownLatch 的源码解析,请看 《【死磕 Java 并发】—– J.U.C 之并发工具类:CountDownLatch》
说说 CyclicBarrier 原理
CyclicBarrier ,字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。
CyclicBarrier 默认的构造方法是 CyclicBarrier(int parties)
,其参数表示屏障拦截的线程数量,每个线程调用 #await()
方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞,直到 parties
个线程到达,结束阻塞。
- CyclicBarrier 的使用示例,请看 《CyclicBarrier 的用法》
- CyclicBarrier 的源码解析,请看 《【死磕 Java 并发】—- J.U.C 之并发工具类:CyclicBarrier》 。
说说 Exchanger 原理
实际场景下,问了一圈朋友,Exchanger 基本没在业务中使用过。
- Exchanger 的使用示例,请看 《【Java并发】线程同步工具Exchanger的使用》 。
- Exchanger 的源码解析,请看 《【死磕 Java 并发】—– J.U.C 之并发工具类:Exchanger》
CyclicBarrier 和 CountdownLatch 有什么区别?
CyclicBarrier 可以重复使用,而 CountdownLatch 不能重复使用。
- CountDownLatch 其实可以把它看作一个计数器,只不过这个计数器的操作是原子操作。
- 你可以向 CountDownLatch 对象设置一个初始的数字作为计数值,任何调用这个对象上的
#await()
方法都会阻塞,直到这个计数器的计数值被其他的线程减为 0 为止。所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier 。 - CountDownLatch 的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个 CountDownLatch 对象的
#await()
方法,其他的任务执行完自己的任务后调用同一个 CountDownLatch 对象上的#countDown()
方法,这个调用#await()
方法的任务将一直阻塞等待,直到这个 CountDownLatch 对象的计数值减到 0 为止。
- 你可以向 CountDownLatch 对象设置一个初始的数字作为计数值,任何调用这个对象上的
- CyclicBarrier 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier 。
整理表格如下:
CountDownLatch | CyclicBarrier |
---|---|
减计数方式 | 加计数方式 |
计算为 0 时释放所有等待的线程 | 计数达到指定值时释放所有等待线程 |
计数为 0 时,无法重置 | 计数达到指定值时,计数置为 0 重新开始 |
调用 #countDown() 方法计数减一,调用 #await() 方法只进行阻塞,对计数没任何影响 |
调用 #await() 方法计数加 1 ,若加 1 后的值不等于构造方法的值,则线程阻塞 |
不可重复利用 | 可重复利用 |
网友评论