Code - Class EDU.oswego.cs.dl.util.concurrent.Semaphore


1 /*
2   File: Semaphore.java
3
4   Originally written by Doug Lea and released into the public domain.
5   This may be used for any purposes whatsoever without acknowledgment.
6   Thanks for the assistance and support of Sun Microsystems Labs,
7   and everyone contributing, testing, and using this code.
8
9   History:
10   Date Who What
11   11Jun1998 dl Create public version
12    5Aug1998 dl replaced int counters with longs
13   24Aug1999 dl release(n): screen arguments
14 */

15
16 package EDU.oswego.cs.dl.util.concurrent;
17
18 /**
19  * Base class for counting semaphores.
20  * Conceptually, a semaphore maintains a set of permits.
21  * Each acquire() blocks if necessary
22  * until a permit is available, and then takes it.
23  * Each release adds a permit. However, no actual permit objects
24  * are used; the Semaphore just keeps a count of the number
25  * available and acts accordingly.
26  * <p>
27  * A semaphore initialized to 1 can serve as a mutual exclusion
28  * lock.
29  * <p>
30  * Different implementation subclasses may provide different
31  * ordering guarantees (or lack thereof) surrounding which
32  * threads will be resumed upon a signal.
33  * <p>
34  * The default implementation makes NO
35  * guarantees about the order in which threads will
36  * acquire permits. It is often faster than other implementations.
37  * <p>
38  * <b>Sample usage.</b> Here is a class that uses a semaphore to
39  * help manage access to a pool of items.
40  * <pre>
41  * class Pool {
42  * static final MAX_AVAILABLE = 100;
43  * private final Semaphore available = new Semaphore(MAX_AVAILABLE);
44  *
45  * public Object getItem() throws InterruptedException { // no synch
46  * available.acquire();
47  * return getNextAvailableItem();
48  * }
49  *
50  * public void putItem(Object x) { // no synch
51  * if (markAsUnused(x))
52  * available.release();
53  * }
54  *
55  * // Not a particularly efficient data structure; just for demo
56  *
57  * protected Object[] items = ... whatever kinds of items being managed
58  * protected boolean[] used = new boolean[MAX_AVAILABLE];
59  *
60  * protected synchronized Object getNextAvailableItem() {
61  * for (int i = 0; i < MAX_AVAILABLE; ++i) {
62  * if (!used[i]) {
63  * used[i] = true;
64  * return items[i];
65  * }
66  * }
67  * return null; // not reached
68  * }
69  *
70  * protected synchronized boolean markAsUnused(Object item) {
71  * for (int i = 0; i < MAX_AVAILABLE; ++i) {
72  * if (item == items[i]) {
73  * if (used[i]) {
74  * used[i] = false;
75  * return true;
76  * }
77  * else
78  * return false;
79  * }
80  * }
81  * return false;
82  * }
83  *
84  * }
85  *</pre>
86  * <p>[<a HREF="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
87 **/

88
89
90 public class Semaphore implements Sync {
91   /** current number of available permits **/
92   protected long permits_;
93
94   /**
95    * Create a Semaphore with the given initial number of permits.
96    * Using a seed of one makes the semaphore act as a mutual exclusion lock.
97    * Negative seeds are also allowed, in which case no acquires will proceed
98    * until the number of releases has pushed the number of permits past 0.
99   **/

100   public Semaphore(long initialPermits) { permits_ = initialPermits; }
101
102
103   /** Wait until a permit is available, and take one **/
104   public void acquire() throws InterruptedException {
105     if (Thread.interrupted()) throw new InterruptedException();
106     synchronized(this) {
107       try {
108         while (permits_ <= 0) wait();
109         --permits_;
110       }
111       catch (InterruptedException ex) {
112         notify();
113         throw ex;
114       }
115     }
116   }
117
118   /** Wait at most msecs millisconds for a permit. **/
119   public boolean attempt(long msecs) throws InterruptedException {
120     if (Thread.interrupted()) throw new InterruptedException();
121
122     synchronized(this) {
123       if (permits_ > 0) {
124         --permits_;
125         return true;
126       }
127       else if (msecs <= 0)
128         return false;
129       else {
130         try {
131           long startTime = System.currentTimeMillis();
132           long waitTime = msecs;
133           
134           for (;;) {
135             wait(waitTime);
136             if (permits_ > 0) {
137               --permits_;
138               return true;
139             }
140             else {
141               waitTime = msecs - (System.currentTimeMillis() - startTime);
142               if (waitTime <= 0)
143                 return false;
144             }
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   /**
163    * Release N permits. <code>release(n)</code> is
164    * equivalent in effect to:
165    * <pre>
166    * for (int i = 0; i < n; ++i) release();
167    * </pre>
168    * <p>
169    * But may be more efficient in some semaphore implementations.
170    * @exception IllegalArgumentException if n is negative.
171    **/

172   public synchronized void release(long n) {
173     if (n < 0) throw new IllegalArgumentException("Negative argument");
174
175     permits_ += n;
176     for (long i = 0; i < n; ++i) notify();
177   }
178
179   /**
180    * Return the current number of available permits.
181    * Returns an accurate, but possibly unstable value,
182    * that may change immediately after returning.
183    **/

184   public synchronized long permits() {
185     return permits_;
186   }
187
188 }
189
190

Java API By Example, From Geeks To Geeks. | Conditions of Use | About Us © 2002 - 2005, KickJava.com, or its affiliates