001: /*
002: File: Semaphore.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: 5Aug1998 dl replaced int counters with longs
013: 24Aug1999 dl release(n): screen arguments
014: */
015:
016: package EDU.oswego.cs.dl.util.concurrent;
017:
018: /**
019: * Base class for counting semaphores.
020: * Conceptually, a semaphore maintains a set of permits.
021: * Each acquire() blocks if necessary
022: * until a permit is available, and then takes it.
023: * Each release adds a permit. However, no actual permit objects
024: * are used; the Semaphore just keeps a count of the number
025: * available and acts accordingly.
026: * <p>
027: * A semaphore initialized to 1 can serve as a mutual exclusion
028: * lock.
029: * <p>
030: * Different implementation subclasses may provide different
031: * ordering guarantees (or lack thereof) surrounding which
032: * threads will be resumed upon a signal.
033: * <p>
034: * The default implementation makes NO
035: * guarantees about the order in which threads will
036: * acquire permits. It is often faster than other implementations.
037: * <p>
038: * <b>Sample usage.</b> Here is a class that uses a semaphore to
039: * help manage access to a pool of items.
040: * <pre>
041: * class Pool {
042: * static final MAX_AVAILABLE = 100;
043: * private final Semaphore available = new Semaphore(MAX_AVAILABLE);
044: *
045: * public Object getItem() throws InterruptedException { // no synch
046: * available.acquire();
047: * return getNextAvailableItem();
048: * }
049: *
050: * public void putItem(Object x) { // no synch
051: * if (markAsUnused(x))
052: * available.release();
053: * }
054: *
055: * // Not a particularly efficient data structure; just for demo
056: *
057: * protected Object[] items = ... whatever kinds of items being managed
058: * protected boolean[] used = new boolean[MAX_AVAILABLE];
059: *
060: * protected synchronized Object getNextAvailableItem() {
061: * for (int i = 0; i < MAX_AVAILABLE; ++i) {
062: * if (!used[i]) {
063: * used[i] = true;
064: * return items[i];
065: * }
066: * }
067: * return null; // not reached
068: * }
069: *
070: * protected synchronized boolean markAsUnused(Object item) {
071: * for (int i = 0; i < MAX_AVAILABLE; ++i) {
072: * if (item == items[i]) {
073: * if (used[i]) {
074: * used[i] = false;
075: * return true;
076: * }
077: * else
078: * return false;
079: * }
080: * }
081: * return false;
082: * }
083: *
084: * }
085: *</pre>
086: * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
087: **/
088:
089: public class Semaphore implements Sync {
090: /** current number of available permits **/
091: protected long permits_;
092:
093: /**
094: * Create a Semaphore with the given initial number of permits.
095: * Using a seed of one makes the semaphore act as a mutual exclusion lock.
096: * Negative seeds are also allowed, in which case no acquires will proceed
097: * until the number of releases has pushed the number of permits past 0.
098: **/
099: public Semaphore(long initialPermits) {
100: permits_ = initialPermits;
101: }
102:
103: /** Wait until a permit is available, and take one **/
104: public void acquire() throws InterruptedException {
105: if (Thread.interrupted())
106: throw new InterruptedException();
107: synchronized (this ) {
108: try {
109: while (permits_ <= 0)
110: wait();
111: --permits_;
112: } catch (InterruptedException ex) {
113: notify();
114: throw ex;
115: }
116: }
117: }
118:
119: /** Wait at most msecs millisconds for a permit. **/
120: public boolean attempt(long msecs) throws InterruptedException {
121: if (Thread.interrupted())
122: throw new InterruptedException();
123:
124: synchronized (this ) {
125: if (permits_ > 0) {
126: --permits_;
127: return true;
128: } else if (msecs <= 0)
129: return false;
130: else {
131: try {
132: long startTime = System.currentTimeMillis();
133: long waitTime = msecs;
134:
135: for (;;) {
136: wait(waitTime);
137: if (permits_ > 0) {
138: --permits_;
139: return true;
140: } else {
141: waitTime = msecs
142: - (System.currentTimeMillis() - startTime);
143: if (waitTime <= 0)
144: return false;
145: }
146: }
147: } catch (InterruptedException ex) {
148: notify();
149: throw ex;
150: }
151: }
152: }
153: }
154:
155: /** Release a permit **/
156: public synchronized void release() {
157: ++permits_;
158: notify();
159: }
160:
161: /**
162: * Release N permits. <code>release(n)</code> is
163: * equivalent in effect to:
164: * <pre>
165: * for (int i = 0; i < n; ++i) release();
166: * </pre>
167: * <p>
168: * But may be more efficient in some semaphore implementations.
169: * @exception IllegalArgumentException if n is negative.
170: **/
171: public synchronized void release(long n) {
172: if (n < 0)
173: throw new IllegalArgumentException("Negative argument");
174:
175: permits_ += n;
176: for (long i = 0; i < n; ++i)
177: notify();
178: }
179:
180: /**
181: * Return the current number of available permits.
182: * Returns an accurate, but possibly unstable value,
183: * that may change immediately after returning.
184: **/
185: public synchronized long permits() {
186: return permits_;
187: }
188:
189: }
|