CountDownLatch用例及源码解析

[align=center]CountDownLatch[/align]

官法解释:一个对同步有帮助的类,它允许一个或多个线程等待只到这组操作在其他线程全部完成.
官司用法:初始是由一个给定的count,await方法可以阻塞只到当前count到达0.这是一个自减机制,比如你初始化 count为5,每调用一次countDown,就减1,只到为0,才释放所有线程,但是这种门插锁机制只有一次有效性,如果你想样多次使用,reset,那么推荐使用CyclicBarrier.
官法用例:
两个countdown latches:
1 阻止所有工人行动,只到司机到来才可以行动.
2 阻止司机行动,只到所有工人的工作都已经完成


package org.countdown;

import java.util.concurrent.CountDownLatch;

public class Driver {

public static void main(String args[]) throws InterruptedException {
int N= 10;
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
print("开始执行...");

for (int i = 0; i < N; ++i){ // create and start threads
print("工人"+i+"到了..");
new Thread(new Worker(startSignal, doneSignal,"工人"+i)).start();
}

print("司机到了"); // don't let run yet
startSignal.countDown(); // let all threads proceed
print("司机完成任务,等待工人完成中...");
doneSignal.await(); // wait for all to finish
print("工人全部完成任务,司机截他们回家");
}

private static void print(String message) {
// TODO Auto-generated method stub
System.out.println(message);
}
}



package org.countdown;

import java.util.concurrent.CountDownLatch;

public class Worker implements Runnable {

private String worker;
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;

Worker(CountDownLatch startSignal, CountDownLatch doneSignal,String worker) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
this.worker = worker;
}

public void run() {
try {

startSignal.await();
doWork();
doneSignal.countDown();
System.out.println(doneSignal.toString());//必须在这里执行,因为在countDown()以上执行是无序的. 只有数了之后才知道还有几个.
} catch (InterruptedException ex) {
} // return;
}

void doWork() {
System.out.println(worker+":劳动完成");
}
}


输出如下:

开始执行...
工人0到了..
工人1到了..
工人2到了..
工人3到了..
工人4到了..
工人5到了..
工人6到了..
工人7到了..
工人8到了..
工人9到了..
司机到了
司机完成任务,等待工人完成中...
工人0:劳动完成
java.util.concurrent.CountDownLatch@1270b73[Count = 9]
工人1:劳动完成
java.util.concurrent.CountDownLatch@1270b73[Count = 8]
工人8:劳动完成
java.util.concurrent.CountDownLatch@1270b73[Count = 7]
工人2:劳动完成
java.util.concurrent.CountDownLatch@1270b73[Count = 6]
工人7:劳动完成
java.util.concurrent.CountDownLatch@1270b73[Count = 5]
工人9:劳动完成
工人5:劳动完成
工人6:劳动完成
java.util.concurrent.CountDownLatch@1270b73[Count = 2]
工人4:劳动完成
java.util.concurrent.CountDownLatch@1270b73[Count = 1]
java.util.concurrent.CountDownLatch@1270b73[Count = 2]
工人3:劳动完成
java.util.concurrent.CountDownLatch@1270b73[Count = 4]
java.util.concurrent.CountDownLatch@1270b73[Count = 0]
工人全部完成任务,司机截他们回家


另一个典型的应用,一个countdown latch:
 在所有工作都完成任务时,和我汇报.
具体见实例2.
其实实例2的功能在实例1已经有了,只是把线程放在Executor上了.

package org.countdown;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Driver2 {

public static void main(String args[]) throws InterruptedException {
int N=10;
CountDownLatch doneSignal = new CountDownLatch(N);
ExecutorService e = Executors.newFixedThreadPool(N);
print("开始执行...");
for (int i = 0; i < N; ++i){ // create and start threads
print("工人"+i+"到了..");
e.execute(new WorkerRunnable(doneSignal, i));
}
System.out.println("所有人都完成了没--没有");
//因为处于多线程环境,这些逻辑代码的执行时候没办法计算,随时可能执行
doneSignal.await(); // wait for all to finish
System.out.println("所有人都完成了没--是的");
//在以上的进行等待后,只有到countDown为0时才会释放,可以保证程序的正常执行顺序.
e.shutdown();
}

private static void print(String message) {
// TODO Auto-generated method stub
System.out.println(message);
}
}



package org.countdown;

import java.util.concurrent.CountDownLatch;

public 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() {
doWork(i);
doneSignal.countDown();
}

void doWork(int i) {
System.out.println("工人" + i + "完成工作");
}

}
输出结果如下:
[code="java"]
开始执行...
工人0到了..
工人1到了..
工人2到了..
工人0完成工作
工人1完成工作
工人3到了..
工人2完成工作
工人4到了..
工人3完成工作
工人4完成工作
工人5到了..
工人6到了..
工人5完成工作
工人7到了..
工人6完成工作
工人8到了..
工人7完成工作
工人9到了..
工人8完成工作
所有人都完成了没--没有
工人9完成工作
所有人都完成了没--是的



[/code]
关键代码解析:
1.  初始化

public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync(int count) {
setState(count);
}
[AbstractQueuedSynchronizer]
protected final void setState(int newState) {
state = newState;
}
private volatile int state;//小技巧,信号量可以用volatile修饰,这也是看源码的好外.


这就是我们调用的初始化方法,其实是设置了一个同步的信号量.
2 等待

public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}

这就是调用我们等待的方法,当CountDown不是0的时候,继续等待下一个线程,如果没有线程可以等待了,那么跳出模块.
3 记数

public void countDown() {
sync.releaseShared(1);
}

每次减1,只到为0.
4 得到记数

public long getCount() {
return sync.getCount();
}


5 打印,挺方便调试的

public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值