1、CountDownLatch能干什么
可以理解为一个计数器。某个线程需要等待这个计数器减到0时,才会继续向下执行。而这个计数器可以在其他线程中递减。这就形成了这种情况,一个线程等待N个线程结束。
例子
import java.util.concurrent.CountDownLatch;
public class CountDownLatchTest {
public static void main(String[] args) {
final CountDownLatch cdl = new CountDownLatch(10);
for (int i = 0; i < 10; i++){
final int j = i;
new Thread(new Runnable() {
@Override
public void run() {
int i = 0;
while(i < Integer.MAX_VALUE){
++i;
}
System.out.println(j);
cdl.countDown();
}
}).start();
}
try {
cdl.await();
System.out.println("here");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
可以看到打印出的结果是,
5
0
2
4
6
8
3
7
1
9
here
在打印出了0-9后,才打印出here,主线程等待了10个子线程结束后才继续向下执行。
2、CountDownLatch分析
和FutureTask的实现相类似,其主要的工作都是在sync中实现,而sync就是AbstractQueuedSynchronizer的实例。
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
private static final class Sync extends AbstractQueuedSynchronizer {
来看看await函数,
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
主要工作都是在sync中实现,来看看acquireSharedInterruptibly是如何实现的, public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
先通过tryAcquireShared来判断是否可以获得锁,如果可以则调用doAcquireSharedInterruptibly进行锁定。此时调用wait函数的线程被挂起,等待countDown唤醒。
protected int tryAcquireShared(int acquires) {
// 这里的state就是传入的参数count,当count捡到0的时候表示不可获得锁。否则可以获得锁
return (getState() == 0) ? 1 : -1;
}
那么来看看计数器是如何递减的。
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
首先通过tryReleaseShared来判断是否可以释放锁,如果可以则调用doReleaseShared来释放锁定。
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
// 获取当前计数
int c = getState();
// 如果c=0,则表示不可释放锁定
if (c == 0)
return false;
// 当前计数递减1
int nextc = c-1;
// 利用原子操作CAS,设置计数为nextc
if (compareAndSetState(c, nextc))
// 当nextc=0时,才表示可以释放锁定
return nextc == 0;
}
}