001: /*
002: File: CountDown.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 CountDown can serve as a simple one-shot barrier.
018: * A Countdown is initialized
019: * with a given count value. Each release decrements the count.
020: * All acquires block until the count reaches zero. Upon reaching
021: * zero all current acquires are unblocked and all
022: * subsequent acquires pass without blocking. This is a one-shot
023: * phenomenon -- the count cannot be reset.
024: * If you need a version that resets the count, consider
025: * using a Barrier.
026: * <p>
027: * <b>Sample usage.</b> Here are a set of classes in which
028: * a group of worker threads use a countdown to
029: * notify a driver when all threads are complete.
030: * <pre>
031: * class Worker implements Runnable {
032: * private final CountDown done;
033: * Worker(CountDown d) { done = d; }
034: * public void run() {
035: * doWork();
036: * done.release();
037: * }
038: * }
039: *
040: * class Driver { // ...
041: * void main() {
042: * CountDown done = new CountDown(N);
043: * for (int i = 0; i < N; ++i)
044: * new Thread(new Worker(done)).start();
045: * doSomethingElse();
046: * done.acquire(); // wait for all to finish
047: * }
048: * }
049: * </pre>
050: *
051: * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
052: *
053: **/
054:
055: public class CountDown implements Sync {
056: protected final int initialCount_;
057: protected int count_;
058:
059: /** Create a new CountDown with given count value **/
060: public CountDown(int count) {
061: count_ = initialCount_ = count;
062: }
063:
064: /*
065: This could use double-check, but doesn't out of concern
066: for surprising effects on user programs stemming
067: from lack of memory barriers with lack of synch.
068: */
069: public void acquire() throws InterruptedException {
070: if (Thread.interrupted())
071: throw new InterruptedException();
072: synchronized (this ) {
073: while (count_ > 0)
074: wait();
075: }
076: }
077:
078: public boolean attempt(long msecs) throws InterruptedException {
079: if (Thread.interrupted())
080: throw new InterruptedException();
081: synchronized (this ) {
082: if (count_ <= 0)
083: return true;
084: else if (msecs <= 0)
085: return false;
086: else {
087: long waitTime = msecs;
088: long start = System.currentTimeMillis();
089: for (;;) {
090: wait(waitTime);
091: if (count_ <= 0)
092: return true;
093: else {
094: waitTime = msecs
095: - (System.currentTimeMillis() - start);
096: if (waitTime <= 0)
097: return false;
098: }
099: }
100: }
101: }
102: }
103:
104: /**
105: * Decrement the count.
106: * After the initialCount'th release, all current and future
107: * acquires will pass
108: **/
109: public synchronized void release() {
110: if (--count_ == 0)
111: notifyAll();
112: }
113:
114: /** Return the initial count value **/
115: public int initialCount() {
116: return initialCount_;
117: }
118:
119: /**
120: * Return the current count value.
121: * This is just a snapshot value, that may change immediately
122: * after returning.
123: **/
124: public synchronized int currentCount() {
125: return count_;
126: }
127: }
|