Java并发-Semaphore & CountDownLatch & CyclicBarrier


  • Semaphore,俗称信号量,它是操作系统中PV操作(P表示通过;V表示释放)的原语在java的实现,它也是基于AbstractQueuedSynchronizer实现的,可以用于做流量控制,特别是公用资源有限的应用场景
    • acquire() 表示阻塞并获取许可
    • tryAcquire() 方法在没有许可的情况下会立即返回 false,要获取许可的线程不会阻塞
    • release() 表示释放许可
    • int availablePermits():返回此信号量中当前可用的许可证数
    • int getQueueLength():返回正在等待获取许可证的线程数
    • boolean hasQueuedThreads():是否有线程正在等待获取许可证
    • void reducePermit(int reduction):减少 reduction 个许可证
    • Collection getQueuedThreads():返回所有等待获取许可证的线程集合
  • CountDownLatch(闭锁)是一个同步协助类,允许一个或多个线程等待,直到其他线程完成操作集
    • CountDownLatch使用给定的计数值(count)初始化。await方法会阻塞直到当前的计数值(count)由于countDown方法的调用达到0,count为0之后所有等待的线程都会被释放,并且随后对await方法的调用都会立即返回。这是一个一次性现象 —— count不会被重置。如果你需要一个重置count的版本,那么请考虑使用CyclicBarrier
    • 底层基于 AbstractQueuedSynchronizer 实现,CountDownLatch 构造函数中指定的count直接赋给AQS的state;每次countDown()则都是release(1)减1,最后减到0时unpark阻塞线程;这一步是由最后一个执行countdown方法的线程执行的
    • 调用await()方法时,当前线程就会判断state属性是否为0,如果为0,则继续往下执行,如果不为0,则使当前线程进入等待状态,直到某个线程将state属性置为0,其就会唤醒在await()方法中等待的线程
  • Thread. join(): 的实现原理是不停检查join线程是否存活,如果 join 线程存活则让当前线程永远等待
  • CyclicBarrier:字面意思回环栅栏(循环屏障),通过它可以实现让一组线程等待至某个状态(屏障点)之后再全部同时执行。叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用
    • CyclicBarrier 可以用于多线程计算数据,最后合并计算结果的场景
  • CountDownLatch与CyclicBarrier的区别
    • CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset() 方法重置
    • CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法
    • CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程
    • CountDownLatch和CyclicBarrier都能够实现线程之间的等待,只不过它们侧重点不同。CountDownLatch一般用于一个或多个线程,等待其他线程执行完任务后,再执行。CyclicBarrier一般用于一组线程互相等待至某个状态,然后这一组线程再同时执行
    • CyclicBarrier 还可以提供一个 barrierAction,合并多线程计算结果
    • CyclicBarrier是通过ReentrantLock的"独占锁"和Conditon来实现一组线程的阻塞唤醒的,而CountDownLatch则是通过AQS的“共享锁”实现

文章作者: 钱不寒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 钱不寒 !
  目录