ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/Semaphore.java
Revision: 1.2
Committed: Tue May 27 18:14:40 2003 UTC (21 years ago) by dl
Branch: MAIN
CVS Tags: JSR166_PRERELEASE_0_1
Changes since 1.1: +95 -9 lines
Log Message:
re-check-in initial implementations

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain. Use, modify, and
4 * redistribute this code in any way without acknowledgement.
5 */
6
7 package java.util.concurrent;
8
9 /**
10 * A counting semaphore. Conceptually, a semaphore maintains a set of
11 * permits. Each {@link #acquire} blocks if necessary until a permit is
12 * available, and then takes it. Each {@link #release} adds a permit,
13 * potentially releasing a blocking acquirer.
14 * However, no actual permit objects are used; the <tt>Semaphore</tt> just
15 * keeps a count of the number available and acts accordingly.
16 *
17 * <p>Semaphores are used to restrict the number of threads than can
18 * access some (physical or logical) resource. For example, here is
19 * a class that uses a semaphore to control access to a pool of items:
20 * <pre>
21 * class Pool {
22 * private static final MAX_AVAILABLE = 100;
23 * private final Semaphore available = new Semaphore(MAX_AVAILABLE);
24 *
25 * public Object getItem() throws InterruptedException {
26 * available.acquire();
27 * return getNextAvailableItem();
28 * }
29 *
30 * public void putItem(Object x) {
31 * if (markAsUnused(x))
32 * available.release();
33 * }
34 *
35 * // Not a particularly efficient data structure; just for demo
36 *
37 * protected Object[] items = ... whatever kinds of items being managed
38 * protected boolean[] used = new boolean[MAX_AVAILABLE];
39 *
40 * protected synchronized Object getNextAvailableItem() {
41 * for (int i = 0; i < MAX_AVAILABLE; ++i) {
42 * if (!used[i]) {
43 * used[i] = true;
44 * return items[i];
45 * }
46 * }
47 * return null; // not reached
48 * }
49 *
50 * protected synchronized boolean markAsUnused(Object item) {
51 * for (int i = 0; i < MAX_AVAILABLE; ++i) {
52 * if (item == items[i]) {
53 * if (used[i]) {
54 * used[i] = false;
55 * return true;
56 * }
57 * else
58 * return false;
59 * }
60 * }
61 * return false;
62 * }
63 *
64 * }
65 * </pre>
66 * <p>Before obtaining an item each thread must acquire a permit from the
67 * semaphore, guaranteeing that an item is available for use. When the
68 * thread has finished with the item it is returned back to the pool and
69 * a permit is returned to the semaphore, allowing another thread to
70 * acquire that item.
71 * Note that no synchronization lock is held when {@link #acquire} is
72 * called as that would prevent an item from being returned to the pool.
73 * The semaphore encapsulates the synchronization needed to restrict access to
74 * the pool, separately from any synchronization needed to maintain the
75 * consistency of the pool itself.
76 *
77 * <p>A semaphore initialized to one, and which is used such that it only
78 * has at most one permit available, can serve as a mutual exclusion lock.
79 * This is more
80 * commonly known as a <em>binary semaphore</em>, because it only has two
81 * states: one permit available, or zero permits available.
82 * When used in this way, the binary semaphore has the property (unlike many
83 * {@link Lock} implementations, that the &quot;lock&quot; can be released by
84 * a thread other than the owner (as semaphores have no notion of ownership).
85 * This can be useful in some specialised contexts, such as deadlock recovery.
86 *
87 * <p>This class makes no guarantees about the order in which threads
88 * acquire permits. In particular, barging is permitted, that is, a thread
89 * invoking {@link #acquire} can be allocated a permit ahead of a thread
90 * that has been waiting. If you need more deterministic guarantees, consider
91 * using {@link FifoSemaphore}.
92 *
93 *
94 * @since 1.5
95 * @spec JSR-166
96 * @revised $Date: 2003/01/29 07:08:21 $
97 * @editor $Author: dholmes $
98 *
99 */
100 public class Semaphore implements java.io.Serializable {
101 // todo SerialID
102 // uses default serialization, which happens be fine here.
103
104 // Fields are package-private to allow the FairSemaphore variant
105 // to access.
106
107 final ReentrantLock lock;
108 final Condition available;
109 long count;
110
111 Semaphore(long permits, ReentrantLock lock) {
112 this.count = permits;
113 this.lock = lock;
114 available = lock.newCondition();
115 }
116
117 /**
118 * Construct a <tt>Semaphore</tt> with the given number of
119 * permits.
120 * @param permits the initial number of permits available
121 */
122 public Semaphore(long permits) {
123 this(permits, new ReentrantLock());
124 }
125
126 /**
127 * Acquires a permit from this semaphore, blocking until one is
128 * available, or the thread is {@link Thread#interrupt interrupted}.
129 *
130 * <p>Acquires a permit, if one is available and returns immediately,
131 * reducing the number of available permits by one.
132 * <p>If no permit is available then the current thread becomes
133 * disabled for thread scheduling purposes and lies dormant until
134 * one of two things happens:
135 * <ul>
136 * <li>Some other thread invokes the {@link #release} method for this
137 * semaphore and the current thread happens to be chosen as the
138 * thread to receive the permit; or
139 * <li>Some other thread {@link Thread#interrupt interrupts} the current
140 * thread.
141 * </ul>
142 *
143 * <p>If the current thread:
144 * <ul>
145 * <li>has its interrupted status set on entry to this method; or
146 * <li>is {@link Thread#interrupt interrupted} while waiting
147 * for a permit,
148 * </ul>
149 * then {@link InterruptedException} is thrown and the current thread's
150 * interrupted status is cleared.
151 *
152 * @throws InterruptedException if the current thread is interrupted
153 *
154 * @see Thread#interrupt
155 */
156 public void acquire() throws InterruptedException {
157 lock.lockInterruptibly();
158 try {
159 while (count <= 0) available.await();
160 --count;
161 }
162 catch (InterruptedException ie) {
163 available.signal();
164 throw ie;
165 }
166 finally {
167 lock.unlock();
168 }
169 }
170
171 /**
172 * Acquires a permit from this semaphore, blocking until one is
173 * available.
174 *
175 * <p>Acquires a permit, if one is available and returns immediately,
176 * reducing the number of available permits by one.
177 * <p>If no permit is available then the current thread becomes
178 * disabled for thread scheduling purposes and lies dormant until
179 * some other thread invokes the {@link #release} method for this
180 * semaphore and the current thread happens to be chosen as the
181 * thread to receive the permit.
182 *
183 * <p>If the current thread
184 * is {@link Thread#interrupt interrupted} while waiting
185 * for a permit then it will continue to wait, but the time at which
186 * the thread is assigned a permit may change compared to the time it
187 * would have received the permit had no interruption occurred. When the
188 * thread does return from this method its interrupt status will be set.
189 *
190 */
191 public void acquireUninterruptibly() {
192 lock.lock();
193 try {
194 while (count <= 0) available.awaitUninterruptibly();
195 --count;
196 }
197 finally {
198 lock.unlock();
199 }
200 }
201
202 /**
203 * Acquires a permit from this semaphore, only if one is available at the
204 * time of invocation.
205 * <p>Acquires a permit, if one is available and returns immediately,
206 * with the value <tt>true</tt>,
207 * reducing the number of available permits by one.
208 *
209 * <p>If no permit is available then this method will return
210 * immediately with the value <tt>false</tt>.
211 *
212 * @return <tt>true</tt> if a permit was acquired and <tt>false</tt>
213 * otherwise.
214 */
215 public boolean tryAcquire() {
216 lock.lock();
217 try {
218 if (count > 0) {
219 --count;
220 return true;
221 }
222 return false;
223 }
224 finally {
225 lock.unlock();
226 }
227 }
228
229 /**
230 * Acquires a permit from this semaphore, if one becomes available
231 * within the given waiting time and the
232 * current thread has not been {@link Thread#interrupt interrupted}.
233 * <p>Acquires a permit, if one is available and returns immediately,
234 * with the value <tt>true</tt>,
235 * reducing the number of available permits by one.
236 * <p>If no permit is available then
237 * the current thread becomes disabled for thread scheduling
238 * purposes and lies dormant until one of three things happens:
239 * <ul>
240 * <li>Some other thread invokes the {@link #release} method for this
241 * semaphore and the current thread happens to be chosen as the
242 * thread to receive the permit; or
243 * <li>Some other thread {@link Thread#interrupt interrupts} the current
244 * thread; or
245 * <li>The specified waiting time elapses.
246 * </ul>
247 * <p>If a permit is acquired then the value <tt>true</tt> is returned.
248 * <p>If the current thread:
249 * <ul>
250 * <li>has its interrupted status set on entry to this method; or
251 * <li>is {@link Thread#interrupt interrupted} while waiting to acquire
252 * a permit,
253 * </ul>
254 * then {@link InterruptedException} is thrown and the current thread's
255 * interrupted status is cleared.
256 * <p>If the specified waiting time elapses then the value <tt>false</tt>
257 * is returned.
258 * The given waiting time is a best-effort lower bound. If the time is
259 * less than or equal to zero, the method will not wait at all.
260 *
261 * @param timeout the maximum time to wait for a permit
262 * @param granularity the time unit of the <tt>timeout</tt> argument.
263 * @return <tt>true</tt> if a permit was acquired and <tt>false</tt>
264 * if the waiting time elapsed before a permit was acquired.
265 *
266 * @throws InterruptedException if the current thread is interrupted
267 *
268 * @see Thread#interrupt
269 *
270 */
271 public boolean tryAcquire(long timeout, TimeUnit granularity)
272 throws InterruptedException {
273 lock.lockInterruptibly();
274 long nanos = granularity.toNanos(timeout);
275 try {
276 for (;;) {
277 if (count > 0) {
278 --count;
279 return true;
280 }
281 if (nanos <= 0)
282 return false;
283 nanos = available.awaitNanos(nanos);
284 }
285 }
286 catch (InterruptedException ie) {
287 available.signal();
288 throw ie;
289 }
290 finally {
291 lock.unlock();
292 }
293 }
294
295 /**
296 * Releases a permit, returning it to the semaphore.
297 * <p>Releases a permit, increasing the number of available permits
298 * by one.
299 * If any threads are blocking trying to acquire a permit, then one
300 * is selected and given the permit that was just released.
301 * That thread is re-enabled for thread scheduling purposes.
302 * <p>There is no requirement that a thread that releases a permit must
303 * have acquired that permit by calling {@link #acquire}.
304 * Correct usage of a semaphore is established by programming convention
305 * in the application.
306 */
307 public void release() {
308 lock.lock();
309 try {
310 ++count;
311 available.signal();
312 }
313 finally {
314 lock.unlock();
315 }
316 }
317
318
319 /**
320 * Return the current number of permits available in this semaphore.
321 * <p>This method is typically used for debugging and testing purposes.
322 * @return the number of permits available in this semaphore.
323 */
324 public long availablePermits() {
325 lock.lock();
326 try {
327 return count;
328 }
329 finally {
330 lock.unlock();
331 }
332 }
333 }
334
335
336