OneShotLatch.java
import java.util.concurrent.locks.*;
/**
* OneShotLatch
* <p/>
* Binary latch using AbstractQueuedSynchronizer
*/
public class OneShotLatch {
private final Sync sync = new Sync();
public void signal() {
sync.releaseShared(0);
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(0);
}
private class Sync extends AbstractQueuedSynchronizer {
protected int tryAcquireShared(int ignored) {
// Succeed if latch is open (state == 1), else fail
return (getState() == 1) ? 1 : -1;
}
protected boolean tryReleaseShared(int ignored) {
setState(1); // Latch is now open
return true; // Other threads may now be able to acquire
}
}
public static void main(String[] args) {
OneShotLatch ol = new OneShotLatch();
Thread t1 = new Thread(() -> {
try {
System.out.println("start await");
ol.await();
System.out.println("finish await");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
System.out.println("signal awaiting thread");
ol.signal();
});
t1.start();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
}
}
The OneShotLatch
class is a classic example of a custom synchronizer built using Java’s low-level AbstractQueuedSynchronizer
(AQS), as explored in Chapter 14 of Java Concurrency in Practice. It functions as a binary latch that starts in a closed state and opens once when signal()
is called, allowing all waiting threads to proceed. The internal Sync
class overrides tryAcquireShared
to block until the latch is opened (i.e., internal state becomes 1), and tryReleaseShared
to set the state to 1 and wake all waiting threads. In the main
method, one thread calls await()
and blocks, while another thread calls signal()
after a delay to release it. This design demonstrates how to implement custom thread coordination primitives using AQS’s shared mode and forms the foundation for constructs like CountDownLatch
.
No comments:
Post a Comment