CountLatch is a thread control mechanism whereby a thread (or many threads) can block by calling await()
on a CountLatch object, which will release when its countDown()
method has been called some number of times.
Since I'm familiar with the concept of thread control with wait()
and notify()
, there is a (to me) obvious implementation of CountLatch, like this:
private volatile int count; // initialised in constructor
public synchronized void countDown() {
count--;
if(count <= 0) {
notifyAll();
}
}
public synchronized void await() throws InterruptedException {
while(count > 0) {
wait();
}
}
However, Java 5 provides its own implementation, java.util.concurrent.CountLatch
which uses an internal class extended from AbstractQueuedSynchronizer
.
private static final class Sync extends AbstractQueuedSynchronizer {
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;
}
}
}
Java 5 CountLatch is essentially a wrapper around this Sync object:
countDown()
calls sync.releaseShared(1)
await()
calls sync.acquireSharedInterruptibly(1)
What is the advantage of this more complex approach?
The main difference between your proposed approach and the JDK is that you are using locks whereas the AbstractQueuedSynchronizer
is lock free and uses Compare-And-Swap internally, which offers better performance under moderate contention.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With