Java 并发工具类

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 为止。
  • CyclicBarrier 一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点 (common barrier point)。在涉及一组固定大小的线程的程序中,这些线程必须不时地互相等待,此时 CyclicBarrier 很有用。因为该 barrier 在释放等待线程后可以重用,所以称它为循环的 barrier 。

整理表格如下:

CountDownLatch CyclicBarrier
减计数方式 加计数方式
计算为 0 时释放所有等待的线程 计数达到指定值时释放所有等待线程
计数为 0 时,无法重置 计数达到指定值时,计数置为 0 重新开始
调用 #countDown() 方法计数减一,调用 #await() 方法只进行阻塞,对计数没任何影响 调用 #await() 方法计数加 1 ,若加 1 后的值不等于构造方法的值,则线程阻塞
不可重复利用 可重复利用

你可能感兴趣的:(Java 并发工具类)