comparison src/EDU/oswego/cs/dl/util/concurrent/Semaphore.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
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