`
xinklabi
  • 浏览: 1587785 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
文章分类
社区版块
存档分类
最新评论

Java并发之CountDownLatch、CyclicBarrier和Semaphore

    博客分类:
  • Java
 
阅读更多

这次说一下 JUC 中的同步器三个主要的成员:CountDownLatch、CyclicBarrier 和 Semaphore(不知道有没有初学者觉得这三个的名字不太好记)。这三个是 JUC 中较为常用的同步器,通过它们可以方便地实现很多线程之间协作的功能。(下面的代码出自 JDK 文档)

CountDownLatch

直译过来就是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的意思顾名思义就是阻止前进。在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程。

作用

CountDownLatch 的作用和 Thread.join() 方法类似,可用于一组线程和另外一组线程的协作。例如,主线程在做一项工作之前需要一系列的准备工作,只有这些准备工作都完成,主线程才能继续它的工作。这些准备工作彼此独立,所以可以并发执行以提高速度。在这个场景下就可以使用 CountDownLatch 协调线程之间的调度了。在直接创建线程的年代(Java 5.0 之前),我们可以使用 Thread.join()。在 JUC 出现后,因为线程池中的线程不能直接被引用,所以就必须使用 CountDownLatch 了。

示例

下面的这个例子可以理解为 F1 赛车的维修过程,只有 startSignal (可以表示停车,可能名字不太贴合)命令下达之后,维修工才开始干活,只有等所有工人完成工作之后,赛车才能继续。

  1. class Driver { // ...  
  2.     void main() throws InterruptedException {  
  3.         CountDownLatch startSignal = new CountDownLatch(1);  
  4.         CountDownLatch doneSignal = new CountDownLatch(N);  
  5.  
  6.         for (int i = 0; i < N; ++i) // create and start threads  
  7.             new Thread(new Worker(startSignal, doneSignal)).start();  
  8.  
  9.         doSomethingElse();            // don't let run yet  
  10.         startSignal.countDown();      // let all threads proceed  
  11.         doSomethingElse();  
  12.         doneSignal.await();           // wait for all to finish  
  13.     }  
  14. }  
  15.  
  16. class Worker implements Runnable {  
  17.     private final CountDownLatch startSignal;  
  18.     private final CountDownLatch doneSignal;  
  19.     Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {  
  20.         this.startSignal = startSignal;  
  21.         this.doneSignal = doneSignal;  
  22.     }  
  23.     public void run() {  
  24.         try {  
  25.             startSignal.await();  
  26.             doWork();  
  27.             doneSignal.countDown();  
  28.         } catch (InterruptedException ex) {} // return;  
  29.     }  
  30.  
  31.     void doWork() { ... }  

当 startSignal.await() 会阻塞线程,当 startSignal.countDown() 被调用之后,所有 Worker 线程开始执行 doWork() 方法,所以 Worker。doWork() 是几乎同时开始执行的。当 Worker.doWork() 执行完毕后,调用 doneSignal.countDown(),在所有 Worker 线程执行完毕之后,主线程继续执行。

CyclicBarrier

CyclicBarrier 翻译过来叫循环栅栏、循环障碍什么的(还是有点别扭的。所以还是别翻译了,只可意会不可言传啊)。它主要的方法就是一个:await()。await() 方法没被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。在这之后,如果再次调用 await() 方法,计数就又会变成 N-1,新一轮重新开始,这便是 Cyclic 的含义所在。

CyclicBarrier 的使用并不难,但需要主要它所相关的异常。除了常见的异常,CyclicBarrier.await() 方法会抛出一个独有的 BrokenBarrierException。这个异常发生在当某个线程在等待本 CyclicBarrier 时被中断或超时或被重置时,其它同样在这个 CyclicBarrier 上等待的线程便会受到 BrokenBarrierException。意思就是说,同志们,别等了,有个小伙伴已经挂了,咱们如果继续等有可能会一直等下去,所有各回各家吧。

CyclicBarrier.await() 方法带有返回值,用来表示当前线程是第几个到达这个 Barrier 的线程。

和 CountDownLatch 一样,CyclicBarrier 同样可以可以在构造函数中设定总计数值。与 CountDownLatch 不同的是,CyclicBarrier 的构造函数还可以接受一个 Runnable,会在 CyclicBarrier 被释放时执行。

  1. “NOTE: CyclicBarrier 的功能也可以由 CountDownLatch 来实现 

示例

CyclicBarrier 的应用(当然,这个例子换成 CountDownLatch 也是可以实现的,很简单,就不说怎么写了)

  1. class Solver {  
  2.     final int N;  
  3.     final float[][] data;  
  4.     final CyclicBarrier barrier;  
  5.  
  6.     class Worker implements Runnable {  
  7.         int myRow;  
  8.         Worker(int row) { myRow = row; }  
  9.         public void run() {  
  10.             while (!done()) {  
  11.                 processRow(myRow);  
  12.  
  13.                 try {  
  14.                     barrier.await();  
  15.                 } catch (InterruptedException ex) {  
  16.                     return;  
  17.                 } catch (BrokenBarrierException ex) {  
  18.                     return;  
  19.                 }  
  20.             }  
  21.         }  
  22.     }  
  23.  
  24.     public Solver(float[][] matrix) {  
  25.         data = matrix;  
  26.         N = matrix.length;  
  27.         barrier = new CyclicBarrier(N, new Runnable() {  
  28.                 public void run() {  
  29.                     mergeRows(...);  
  30.                 }  
  31.             });  
  32.         for (int i = 0; i < N; ++i)  
  33.             new Thread(new Worker(i)).start();  
  34.  
  35.         waitUntilDone();  
  36.     }  

CyclicBarrier 和 CountDownLatch 在用法上的不同

CountDownLatch 适用于一组线程和另一个主线程之间的工作协作。一个主线程等待一组工作线程的任务完毕才继续它的执行是使用 CountDownLatch 的主要场景;CyclicBarrier 用于一组或几组线程,比如一组线程需要在一个时间点上达成一致,例如同时开始一个工作。另外,CyclicBarrier 的循环特性和构造函数所接受的 Runnable 参数也是 CountDownLatch 所不具备的。

Semaphore

Semaphore 直译是信号量,可能称它是许可量更容易理解。当然,因为在计算机科学中这个名字由来已久,所以不能乱改。它的功能比较好理解,就是通过构造函数设定一个数量的许可,然后通过 acquire 方法获得许可,release 方法释放许可。它还有 tryAcquire 和 acquireUninterruptibly 方法,可以根据自己的需要选择

示例:Semaphore 控制资源访问

  1. class Pool {  
  2.     private static final int MAX_AVAILABLE = 100;  
  3.     private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);  
  4.  
  5.     public Object getItem() throws InterruptedException {  
  6.         available.acquire();  
  7.         return getNextAvailableItem();  
  8.     }  
  9.  
  10.     public void putItem(Object x) {  
  11.         if (markAsUnused(x))  
  12.             available.release();  
  13.     }  
  14.  
  15.     // Not a particularly efficient data structure; just for demo  
  16.  
  17.     protected Object[] items = ... whatever kinds of items being managed  
  18.     protected boolean[] used = new boolean[MAX_AVAILABLE];  
  19.  
  20.     protected synchronized Object getNextAvailableItem() {  
  21.         for (int i = 0; i < MAX_AVAILABLE; ++i) {  
  22.             if (!used[i]) {  
  23.                 used[i] = true;  
  24.                 return items[i];  
  25.             }  
  26.         }  
  27.         return null// not reached  
  28.     }  
  29.  
  30.     protected synchronized boolean markAsUnused(Object item) {  
  31.         for (int i = 0; i < MAX_AVAILABLE; ++i) {  
  32.             if (item == items[i]) {  
  33.                 if (used[i]) {  
  34.                     used[i] = false;  
  35.                     return true;  
  36.                 } else 
  37.                     return false;  
  38.             }  
  39.         }  
  40.         return false;  
  41.     }  

上面这个示例中 Semaphore 的用法没什么可多讲的。需要留言的是这里面有两个同步方法,不过对吞吐应该没什么影响,因为主要是对一个 boolean 数组做一下 O(n) 的操作,而且每个循环里面的操作很简单,所以速度很快。不过不知道 JUC 里面线程池的控制是怎么做的,本人不才,还没看过那块源代码,得空看看,有知道的也可以说说。

最后一句话总结

CountDownLatch 是能使一组线程等另一组线程都跑完了再继续跑;CyclicBarrier 能够使一组线程在一个时间点上达到同步,可以是一起开始执行全部任务或者一部分任务。同时,它是可以循环使用的;Semaphore 是只允许一定数量的线程同时执行一段任务。

原文链接:http://my.oschina.net/lifany/blog/207995

分享到:
评论

相关推荐

    Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解

    Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解 Java并发编程是Java语言中的一种高级技术,用于处理多线程编程中的同步问题。Java 1.5中引入了几个高效的辅助类,包括CountDownLatch、...

    Java并发编程一CountDownLatch、CyclicBarrier、Semaphore初使用

    在Java并发编程中,CountDownLatch、CyclicBarrier和Semaphore是三种重要的线程协作工具,它们都基于AbstractQueuedSynchronizer(AQS)框架来实现线程间的同步和协调。AQS是一个内置的锁和同步组件,它为构建高级...

    CountDownLatch、CyclicBarrier、Semaphore.md

    java 高并发应用场景

    Java并发编程-3.pdf

    CountDownLatch、CyclicBarrier 和 Semaphore 等多线程协作机制都是 Java 并发编程中的重要组成部分。它们可以帮助开发者编写高效、可靠的多线程程序,解决复杂的并发问题。 在实际开发中,我们可以根据具体情况...

    CountDownLatch、Semaphore等4大并发工具类详解

    本文将详细介绍 Java 并发工具类的四大类:CountDownLatch、Semaphore、CyclicBarrier 和 Phaser,及其应用场景和使用方法。 CountDownLatch CountDownLatch 是一个同步的辅助类,允许一个或多个线程,等待其他一...

    Java并发编程常识-梁飞.rar

    并发工具类,如CountDownLatch、CyclicBarrier、Semaphore等,提供了协调多线程执行的机制。CountDownLatch允许一个或多个线程等待其他线程完成操作;CyclicBarrier则允许一组线程等待彼此到达某个屏障点;Semaphore...

    《java 并发编程实战高清PDF版》

    其中包括`Semaphore`(信号量)用于限制同时访问特定资源的线程数量,`CountDownLatch`(倒计时器)用于一次性阻塞多个线程,直到某个事件发生,以及`CyclicBarrier`(循环栅栏)让一组线程等待其他线程到达特定点后...

    java并发编程艺术

    此外,书中可能还会涉及其他并发编程相关的高级话题,比如原子变量(`AtomicInteger`, `AtomicReference`等)、并发工具类(如`CountDownLatch`, `CyclicBarrier`, `Semaphore`)以及Fork/Join框架。这些工具可以...

    java并发变成实战

    其次,书中会深入讲解Java提供的并发工具类,如Executor框架、ThreadLocal、CountDownLatch、CyclicBarrier、Semaphore等。Executor框架允许我们更灵活地管理和调度线程,避免过度依赖线程的创建和销毁;ThreadLocal...

    Java并发编程设计原则和模式

    在Java编程领域,并发编程是一项核心技能,尤其是在多核处理器和分布式系统中,它能显著提升应用程序的性能和响应速度。本资料“Java并发编程设计原则和模式”深入探讨了如何在Java环境中有效地进行并发处理,以充分...

    java并发编程2

    - **`java.util.concurrent` 包** 提供了丰富的并发工具类,如`ExecutorService`用于管理线程池,`Semaphore`用于许可证管理,`CountDownLatch`用于同步多个线程,`CyclicBarrier`用于多线程间的协作等。...

    Java并发编程实践高清pdf及源码

    5. **并发工具类**:如`CountDownLatch`、`CyclicBarrier`、`Semaphore`和`Phaser`等,它们为多线程间的协作提供了方便。 6. **活锁与死锁**:活锁是两个或更多线程相互等待对方释放资源,导致无限期等待;死锁则是...

    JAVA并发编程艺术pdf版

    - **java.util.concurrent** 包:提供了各种并发工具类,如Semaphore(信号量)、CyclicBarrier(循环屏障)、CountDownLatch(倒计时器)和ExecutorService(线程池)等。 - **Future和Callable**:Future接口...

    JAVA并发编程实践 pdf

    Java提供了一套丰富的并发工具类,如Executor框架、Future、Callable、CountDownLatch、CyclicBarrier、Semaphore等。这些工具可以帮助开发者更好地管理和控制并发任务,提高代码的灵活性和可维护性。书中将详细讲解...

    Java并发编程从入门到精通(pdf)(附源码)

    接着,书中将深入探讨Java并发工具类,如Executor框架、Semaphore信号量、CyclicBarrier和CountDownLatch等,这些工具在实际项目中有着广泛的应用,学习它们能帮助开发者更好地控制和协调并发任务。 此外,书中的...

    Java并发编程_设计原则和模式(CHM)

    如CountDownLatch、CyclicBarrier、Semaphore等,它们在多线程协作和控制流程中起到关键作用。 九、线程通信 Java提供了wait()、notify()和notifyAll()方法来进行线程间的通信,但使用时必须在同步块内,否则会抛出...

    java并发编程与实践

    3. **并发工具类**:Java并发包(java.util.concurrent)包含了许多工具类,如Semaphore(信号量)、CyclicBarrier(回环屏障)、CountDownLatch(计数器门锁)和ThreadPoolExecutor(线程池)。这些工具可以帮助...

    Java并发编程全景图.pdf

    Java并发工具类扩展了基本的并发功能,例如CountDownLatch、CyclicBarrier、Semaphore和Phaser提供了不同场景下的同步支持。Exchanger用于两个线程之间交换数据。 12. 硬件和操作系统支持 Java并发编程的成功在很大...

    java并发编程实践pdf笔记

    - `java.util.concurrent`包提供了一系列的并发工具类,如`Semaphore`(信号量)、`CountDownLatch`(计数器)、`CyclicBarrier`(回环栅栏)等,它们为复杂的并发场景提供了强大的支持。 - **并发集合** 如`...

Global site tag (gtag.js) - Google Analytics