ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/Semaphore.java
Revision: 1.9
Committed: Mon Aug 25 19:27:58 2003 UTC (20 years, 9 months ago) by dl
Branch: MAIN
Changes since 1.8: +4 -4 lines
Log Message:
serialVersionUIDs

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