001: /*
002: File: Latch.java
003:
004: Originally written by Doug Lea and released into the public domain.
005: This may be used for any purposes whatsoever without acknowledgment.
006: Thanks for the assistance and support of Sun Microsystems Labs,
007: and everyone contributing, testing, and using this code.
008:
009: History:
010: Date Who What
011: 11Jun1998 dl Create public version
012: */
013:
014: package EDU.oswego.cs.dl.util.concurrent;
015:
016: /**
017: * A latch is a boolean condition that is set at most once, ever.
018: * Once a single release is issued, all acquires will pass.
019: * <p>
020: * <b>Sample usage.</b> Here are a set of classes that use
021: * a latch as a start signal for a group of worker threads that
022: * are created and started beforehand, and then later enabled.
023: * <pre>
024: * class Worker implements Runnable {
025: * private final Latch startSignal;
026: * Worker(Latch l) { startSignal = l; }
027: * public void run() {
028: * startSignal.acquire();
029: * doWork();
030: * }
031: * void doWork() { ... }
032: * }
033: *
034: * class Driver { // ...
035: * void main() {
036: * Latch go = new Latch();
037: * for (int i = 0; i < N; ++i) // make threads
038: * new Thread(new Worker(go)).start();
039: * doSomethingElse(); // don't let run yet
040: * go.release(); // let all threads proceed
041: * }
042: * }
043: *</pre>
044: * [<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>] <p>
045: **/
046:
047: public class Latch implements Sync {
048: protected boolean latched_ = false;
049:
050: /*
051: This could use double-check, but doesn't.
052: If the latch is being used as an indicator of
053: the presence or state of an object, the user would
054: not necessarily get the memory barrier that comes with synch
055: that would be needed to correctly use that object. This
056: would lead to errors that users would be very hard to track down. So, to
057: be conservative, we always use synch.
058: */
059:
060: public void acquire() throws InterruptedException {
061: if (Thread.interrupted())
062: throw new InterruptedException();
063: synchronized (this ) {
064: while (!latched_)
065: wait();
066: }
067: }
068:
069: public boolean attempt(long msecs) throws InterruptedException {
070: if (Thread.interrupted())
071: throw new InterruptedException();
072: synchronized (this ) {
073: if (latched_)
074: return true;
075: else if (msecs <= 0)
076: return false;
077: else {
078: long waitTime = msecs;
079: long start = System.currentTimeMillis();
080: for (;;) {
081: wait(waitTime);
082: if (latched_)
083: return true;
084: else {
085: waitTime = msecs
086: - (System.currentTimeMillis() - start);
087: if (waitTime <= 0)
088: return false;
089: }
090: }
091: }
092: }
093: }
094:
095: /** Enable all current and future acquires to pass **/
096: public synchronized void release() {
097: latched_ = true;
098: notifyAll();
099: }
100:
101: }
|