这次说一下 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 (可以表示停车,可能名字不太贴合)命令下达之后,维修工才开始干活,只有等所有工人完成工作之后,赛车才能继续。
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
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
被释放时执行。
NOTE: CyclicBarrier 的功能也可以由 CountDownLatch 来实现
示例
CyclicBarrier 的应用(当然,这个例子换成 CountDownLatch 也是可以实现的,很简单,就不说怎么写了)
class Solver {
final int N;
final float[][] data;
final CyclicBarrier barrier;
class Worker implements Runnable {
int myRow;
Worker(int row) { myRow = row; }
public void run() {
while (!done()) {
processRow(myRow);
try {
barrier.await();
} catch (InterruptedException ex) {
return;
} catch (BrokenBarrierException ex) {
return;
}
}
}
}
public Solver(float[][] matrix) {
data = matrix;
N = matrix.length;
barrier = new CyclicBarrier(N, new Runnable() {
public void run() {
mergeRows(...);
}
});
for (int i = 0; i < N; ++i)
new Thread(new Worker(i)).start();
waitUntilDone();
}
}
CyclicBarrier
和 CountDownLatch
在用法上的不同
CountDownLatch
适用于一组线程和另一个主线程之间的工作协作。一个主线程等待一组工作线程的任务完毕才继续它的执行是使用 CountDownLatch
的主要场景;CyclicBarrier
用于一组或几组线程,比如一组线程需要在一个时间点上达成一致,例如同时开始一个工作。另外,CyclicBarrier
的循环特性和构造函数所接受的 Runnable
参数也是 CountDownLatch
所不具备的。
Semaphore
Semaphore
直译是信号量,可能称它是许可量更容易理解。当然,因为在计算机科学中这个名字由来已久,所以不能乱改。它的功能比较好理解,就是通过构造函数设定一个数量的许可,然后通过 acquire
方法获得许可,release
方法释放许可。它还有 tryAcquire
和 acquireUninterruptibly
方法,可以根据自己的需要选择
示例:Semaphore
控制资源访问
class Pool {
private static final int MAX_AVAILABLE = 100;
private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
public Object getItem() throws InterruptedException {
available.acquire();
return getNextAvailableItem();
}
public void putItem(Object x) {
if (markAsUnused(x))
available.release();
}
// Not a particularly efficient data structure; just for demo
protected Object[] items = ... whatever kinds of items being managed
protected boolean[] used = new boolean[MAX_AVAILABLE];
protected synchronized Object getNextAvailableItem() {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (!used[i]) {
used[i] = true;
return items[i];
}
}
return null; // not reached
}
protected synchronized boolean markAsUnused(Object item) {
for (int i = 0; i < MAX_AVAILABLE; ++i) {
if (item == items[i]) {
if (used[i]) {
used[i] = false;
return true;
} else
return false;
}
}
return false;
}
}
上面这个示例中 Semaphore 的用法没什么可多讲的。需要留言的是这里面有两个同步方法,不过对吞吐应该没什么影响,因为主要是对一个 boolean 数组做一下 O(n) 的操作,而且每个循环里面的操作很简单,所以速度很快。不过不知道 JUC 里面线程池的控制是怎么做的,本人不才,还没看过那块源代码,得空看看,有知道的也可以说说。
最后一句话总结
CountDownLatch
是能使一组线程等另一组线程都跑完了再继续跑;CyclicBarrier
能够使一组线程在一个时间点上达到同步,可以是一起开始执行全部任务或者一部分任务。同时,它是可以循环使用的;Semaphore
是只允许一定数量的线程同时执行一段任务。
转自:http://my.oschina.net/lifany/blog/207995
相关推荐
本文将详细介绍 Java 并发工具类的四大类:CountDownLatch、Semaphore、CyclicBarrier 和 Phaser,及其应用场景和使用方法。 CountDownLatch CountDownLatch 是一个同步的辅助类,允许一个或多个线程,等待其他一...
java 高并发应用场景
在Java并发编程中,CountDownLatch、CyclicBarrier和Semaphore是三种重要的线程协作工具,它们都基于AbstractQueuedSynchronizer(AQS)框架来实现线程间的同步和协调。AQS是一个内置的锁和同步组件,它为构建高级...
Java并发编程:CountDownLatch与CyclicBarrier和Semaphore的实例详解 Java并发编程是Java语言中的一种高级技术,用于处理多线程编程中的同步问题。Java 1.5中引入了几个高效的辅助类,包括CountDownLatch、...
AQS 通过 `tryAcquire()` 和 `tryRelease()` 方法控制线程的获取和释放同步状态,而这些方法是由具体实现类(如 ReentrantLock、Semaphore、CountDownLatch 等)来定义的。 **总结:** CountDownLatch 和 ...
CountDownLatch CyclicBarrier Semaphore 什么是自旋锁(CAS,compare and swap)? CAS存在的问题 什么是读写锁? 谈谈并发编程三要素 简述Java内存模型(JMM) volatile关键字知道么,它是怎么实现的?(难点 重要) ...
java forkjoin 源码 JDK源码学习: Java 容器 ArrayList LinkedList PriorityQueue ...CountDownLatch CyclicBarrier Semaphore ForkJoin FutureTask BlockingQueue Spring AOP IOC 面向面经复习
第一章:Java并发简介 1.1 什么是并发编程 1.2 Java中的并发编程模型 1.3 线程的生命周期 第二章:基础同步工具 2.1 synchronized关键字 2.2 volatile关键字 第三章:锁机制 3.1 ReentrantLock 3.2 ...
leetcode下载 newbie-notes 创建该项目是为了记录自己的一些笔记 ...CountDownLatch CyclicBarrier Semaphore Atomic 原子类型 Executor 线程池 ThreadLocal 用法 一些优秀的仓库 spring framework
Java 提供了多种多线程协作机制,包括CountDownLatch、CyclicBarrier、Semaphore 等。 1. CountDownLatch CountDownLatch 是一种同步工具,允许一个或多个线程等待直到某些操作完成。它可以用来实现线程之间的同步...
如果需要一部分线程完成即可继续,可以选择CyclicBarrier或Semaphore。 在实际编程中,熟练掌握CountDownLatch可以帮助我们更有效地编写高并发程序,解决复杂的同步问题。通过阅读和理解提供的代码样例(如`...
CountDownLatch CyclicBarrier Semaphore Exchange 并发编程容器collections 并发Queue:BlockingQueue Map:ConcurrentHashMap、HashMap、HashTable 并发List Set:CopyOnWriteArrayList、CopyOnWriteArraySet、 ...
CountDownLatch/CyclicBarrier/Semaphore CountDownLatch 枚举类的使用 CyclicBarrier Semaphore 阻塞队列 SynchronousQueue Callable接口 阻塞队列的应用——生产者消费者 传统模式 阻塞队列模式 阻塞队列的应用...
如果需要重复使用,考虑使用CyclicBarrier或Semaphore等其他同步工具。 - 误用可能导致死锁,比如计数器设置过大或者`countDown()`未正确调用,可能会导致等待的线程永久阻塞。 通过对`countdownlatch-example-...
java并发,主要用于初学者学习,主要案列,Thread.join,ThreadLocal,Lock接口,LockSupport,Condition接口,ConcurrentHashMap的实现原理与...Fork/Join 框架,CountDownLatch,CyclicBarrier,Semaphore,Exchanger
有以下类的实例: ThreadPool ScheduledThread CyclicBarrier BlockingQueue CountDownLatch FutureTask CompletionService Semaphore
Java 并发工具类中有很多种,今天我们主要介绍四种:CyclicBarrier、CountDownLatch、Semaphore 和 Exchanger。 一、CyclicBarrier CyclicBarrier 是一种同步工具,允许一组线程互相等待,直到到达某个公共屏障点...
多线程控制的三大安全类:CountDownLatch、CyclicBarrier、Semaphore,这工具包将其封装,可以让初学者更容易学习以及让开发者更容易调用,不需要自己重新编写核心代码。具体事例在源码中。
同步工具类:concurrent包提供了一些同步工具类,如CountDownLatch、CyclicBarrier、Semaphore等,可以帮助开发者实现复杂的线程协作和同步任务。 并发集合类:concurrent包提供了一些并发集合类,如...