JDK-CountDownLatch-实例、源码和模拟实现(二)

2014-11-24 09:17:16 · 作者: · 浏览: 5
@Override
public void run() {
try {
this.beginCount.await();
System.out.println(this.name + " start.");
Thread.currentThread().sleep(this.runningTime);
System.out.println(this.name + " breast the tape.");
this.endCount.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Source Code
我们来看JDK中CountDownLatch是怎么定义的,以及其中的主要方法。
[java]
public class CountDownLatch {
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public void countDown() {
sync.releaseShared(1);
}
public long getCount() {
return sync.getCount();
}
}
很显然,CountDownLatch的逻辑都封装在内部类Sync中,这也是通过装饰者模式来提高封装性的普遍做法。
Sync继承了AbstractQueuedSynchronizer,这里的调用关系有点麻烦,我就不一一展开了,我贴了部分关键的代码(如下)。
概括一下,CountDownLatch的count存放在以volatile声明的变量state。在await()的时候for轮询state,一直轮询以达到阻塞的效果,直到state==0。而countDown()就是通过CompareAndSet的方式来递减state。
[java]
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) 1 : -1;
}
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))
return nextc == 0;
}
}
}
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer {
private volatile int state;
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
}
Simulator
从上面可以看出来,其实CountDownLatch的实现很简单,countDown的时候原子修改,await的时候循环判断volatile来阻塞。
所以完全可以通过原子类来实现,而且还更加beautiful。以下,我用AtomicInteger来模拟CountDownLatch的实现。
测试程序还是和上面的赛跑程序一样的,只是把CountDownLatch替换成了CountDownLatchSimulator。
最后测试结果还是一样的,只是过程简单了许多,因为JDK把很多防止冲突的逻辑都封装在原子类了。其中await的时候,可以在循环中加上sleep,能减低 系统轮询的消耗。
【我只是做了一个简单的实现,至于性能和安全性方面,还希望大神们指导】
[java]
public class CountDownLatchSimulator {