CountDownLatch几个经常用的方法分析
CountDownLatch构造函数
public CountDownLatch(int count) {
if (count < 0) throw new
IllegalArgumentException("count < 0");
//此处调用CountDownLatch的队列同步器
this.sync = new Sync(count);
}
//设置state
Sync(int count) {
setState(count);
}
CountDownLatch的await()
/**
* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
*
* <p>If the current count is zero then this method returns immediately.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of two things happen:
*/
//上面翻译大意是:当前线程等待直到state到0时
//除非被打断
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//调用模板方法中的tryAcquireShared(arg)
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
//当获取到state是否等于0,返回1或者-1
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
CountDownLatch中的countDown()
/**
* Decrements the count of the latch, releasing all waiting threads if
* the count reaches zero.
*
* <p>If the current count is greater than zero then it is decremented.
* If the new count is zero then all waiting threads are re-enabled for
* thread scheduling purposes.
*
* <p>If the current count equals zero then nothing happens.
*/
//减少state数量,如果到达0,释放所有正在等待的线程
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
//这是CountDownLatch类型重写的模板方法
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
//只有等于0的时候才会返回true
return nextc == 0;
}
}
CountDownLatch的官方示例
* class Driver2 { // ...
* void main() throws InterruptedException {
* CountDownLatch doneSignal = new CountDownLatch(N);
* Executor e = ...
*
* for (int i = 0; i < N; ++i) // create and start threads
* e.execute(new WorkerRunnable(doneSignal, i));
*
* doneSignal.await(); // wait for all to finish
* }
* }
*
* class WorkerRunnable implements Runnable {
* private final CountDownLatch doneSignal;
* private final int i;
* WorkerRunnable(CountDownLatch doneSignal, int i) {
* this.doneSignal = doneSignal;
* this.i = i;
* }
* public void run() {
* try {
* doWork(i);
* doneSignal.countDown();
* } catch (InterruptedException ex) {} // return;
* }
*
* void doWork() { ... }
* }}</pre>
*
原理
构造函数N,调用await()开始,知道countDown()N次,才会继续执行后续操作
具体原理,就是await()也就是lock()当前线程,(上述的例子中是main线程),后面会调用
countDown()N次,才会unlock()当前线程
CyclicBarrier例子
同时计算N个示例,计算完N个示例,执行runnable里面的run()方法
import java.util.Map;
import java.util.concurrent.*;
public class BankWaterService implements Runnable{
//创建4个屏障,处理完之后执行当前类的run方法
private CyclicBarrier cyclicBarrier = new CyclicBarrier(4,this);
//假如只有4个sheet,所以启动4个线程
private ExecutorService executor = Executors.newFixedThreadPool(4);
private ConcurrentHashMap<String,Integer> sheetBankWaterCount = new ConcurrentHashMap<String,Integer>();
private void count(){
try {
for (int i = 0; i < 4; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
//计算当前i对应的sheet的银流数据,计算代码省略
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
sheetBankWaterCount.put(Thread.currentThread().getName(), 1);
//银流计算完成,插入一个屏障
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
});
}
}finally {
executor.shutdown();
}
}
@Override
public void run(){
int result = 0;
for(Map.Entry<String,Integer> sheet : sheetBankWaterCount.entrySet()){
result += sheet.getValue();
}
System.out.println(result);
}
public static void main(String[] args) {
BankWaterService bankWaterService = new BankWaterService();
bankWaterService.count();
}
}
上述代码,是为了执行计算多个sheet中的数据,最后执行合计
来测试runnable到底是最先执行还是最后执行
public class CyclicBarrierTest2 {
static CyclicBarrier cyclicBarrier = new CyclicBarrier(2,new A());
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(1);
}
}).start();
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(2);
}
static class A implements Runnable{
@Override
public void run() {
System.out.println(3);
}
}
}
//输出结果
3
1
2
源码分析
要知道源码中调用的是ReentrantLock可重入式锁
/**
* Main barrier code, covering the various policies.
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock;
lock.lock();
try {
final Generation g = generation;
if (g.broken)
throw new BrokenBarrierException();
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
int index = --count;
//可以看到,执行了多个await()之后,导致count==0时,才会执行下面代码
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
//这个地方最搞笑的是他直接run了。
command.run();
ranAction = true;
//此处是为下一波僵尸来临做准备
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
/**
* Updates state on barrier trip and wakes up everyone.
* Called only while holding lock.
*/
private void nextGeneration() {
// signal completion of last generation
trip.signalAll();
// set up next generation
//重新给count赋了值,parties也就是构造函数里面的值
count = parties;
generation = new Generation();
}
await()这个考虑更多的是,你的线程业务执行完后,再调用await()才好执行。直到执行到最后一个,才会正在的unlock();
展示一波,cyclicBarrier重用
public class CyclicBarrierTest3 {
static class Writer extends Thread{
private CyclicBarrier cyclicBarrier;
public Writer(CyclicBarrier cyclicBarrier){
this.cyclicBarrier = cyclicBarrier;
}
@Override
public void run() {
System.out.println("线程" + Thread.currentThread().getName() + "正在写入数据...");
try {
Thread.sleep(5000);
System.out.println("线程" + Thread.currentThread().getName() + "写入数据完毕,等待其他线程写入");
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
}catch (BrokenBarrierException e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "所有线程写入完毕,继续处理其他任务");
}
}
public static void main(String[] args) {
int N = 4;
CyclicBarrier cyclicBarrier = new CyclicBarrier(N);
for(int i = 0 ;i < N ;i++){
new Writer(cyclicBarrier).start();
}
try {
Thread.sleep(25000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Cyclicbarrier重用");
for(int i = 0 ;i < N ;i++){
new Writer(cyclicBarrier).start();
}
}
}
//输出结果
线程Thread-0正在写入数据...
线程Thread-2正在写入数据...
线程Thread-1正在写入数据...
线程Thread-3正在写入数据...
线程Thread-2写入数据完毕,等待其他线程写入
线程Thread-0写入数据完毕,等待其他线程写入
线程Thread-1写入数据完毕,等待其他线程写入
线程Thread-3写入数据完毕,等待其他线程写入
Thread-2所有线程写入完毕,继续处理其他任务
Thread-1所有线程写入完毕,继续处理其他任务
Thread-3所有线程写入完毕,继续处理其他任务
Thread-0所有线程写入完毕,继续处理其他任务
Cyclicbarrier重用
线程Thread-4正在写入数据...
线程Thread-5正在写入数据...
线程Thread-6正在写入数据...
线程Thread-7正在写入数据...
线程Thread-4写入数据完毕,等待其他线程写入
线程Thread-6写入数据完毕,等待其他线程写入
线程Thread-7写入数据完毕,等待其他线程写入
线程Thread-5写入数据完毕,等待其他线程写入
Thread-5所有线程写入完毕,继续处理其他任务
Thread-4所有线程写入完毕,继续处理其他任务
Thread-6所有线程写入完毕,继续处理其他任务
Thread-7所有线程写入完毕,继续处理其他任务
还有部分代码来自:《java并发编程的艺术》