ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/Semaphore.java
Revision: 1.13
Committed: Sat Sep 27 12:22:40 2003 UTC (20 years, 8 months ago) by dl
Branch: MAIN
Changes since 1.12: +3 -3 lines
Log Message:
Use "unit" instead of "granularity"; add Executors link to first sentence of TPE

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 specialized 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 * @author Doug Lea
96 *
97 */
98 public class Semaphore implements java.io.Serializable {
99 private static final long serialVersionUID = 3217036696412297181L;
100
101
102 // Fields are package-private to allow the FairSemaphore variant
103 // to access.
104
105 final ReentrantLock lock;
106 final Condition available;
107 long count;
108
109 /**
110 * Package-private constructor used by FairSemaphore
111 * @param permits the initial number of permits available
112 * @param lock the lock to use
113 */
114 Semaphore(long permits, ReentrantLock lock) {
115 this.count = permits;
116 this.lock = lock;
117 available = lock.newCondition();
118 }
119
120 /**
121 * Construct a <tt>Semaphore</tt> with the given number of
122 * permits.
123 * @param permits the initial number of permits available
124 */
125 public Semaphore(long permits) {
126 this(permits, new ReentrantLock());
127 }
128
129 /**
130 * Acquires a permit from this semaphore, blocking until one is
131 * available, or the thread is {@link Thread#interrupt interrupted}.
132 *
133 * <p>Acquires a permit, if one is available and returns immediately,
134 * reducing the number of available permits by one.
135 * <p>If no permit is available then the current thread becomes
136 * disabled for thread scheduling purposes and lies dormant until
137 * one of two things happens:
138 * <ul>
139 * <li>Some other thread invokes the {@link #release} method for this
140 * semaphore and the current thread happens to be chosen as the
141 * thread to receive the permit; or
142 * <li>Some other thread {@link Thread#interrupt interrupts} the current
143 * thread.
144 * </ul>
145 *
146 * <p>If the current thread:
147 * <ul>
148 * <li>has its interrupted status set on entry to this method; or
149 * <li>is {@link Thread#interrupt interrupted} while waiting
150 * for a permit,
151 * </ul>
152 * then {@link InterruptedException} is thrown and the current thread's
153 * interrupted status is cleared.
154 *
155 * @throws InterruptedException if the current thread is interrupted
156 *
157 * @see Thread#interrupt
158 */
159 public void acquire() throws InterruptedException {
160 lock.lockInterruptibly();
161 try {
162 while (count <= 0)
163 available.await();
164 --count;
165 } catch (InterruptedException ie) {
166 available.signal();
167 throw ie;
168 } finally {
169 lock.unlock();
170 }
171 }
172
173 /**
174 * Acquires a permit from this semaphore, blocking until one is
175 * available.
176 *
177 * <p>Acquires a permit, if one is available and returns immediately,
178 * reducing the number of available permits by one.
179 * <p>If no permit is available then the current thread becomes
180 * disabled for thread scheduling purposes and lies dormant until
181 * some other thread invokes the {@link #release} method for this
182 * semaphore and the current thread happens to be chosen as the
183 * thread to receive the permit.
184 *
185 * <p>If the current thread
186 * is {@link Thread#interrupt interrupted} while waiting
187 * for a permit then it will continue to wait, but the time at which
188 * the thread is assigned a permit may change compared to the time it
189 * would have received the permit had no interruption occurred. When the
190 * thread does return from this method its interrupt status will be set.
191 *
192 */
193 public void acquireUninterruptibly() {
194 lock.lock();
195 try {
196 while (count <= 0)
197 available.awaitUninterruptibly();
198 --count;
199 } finally {
200 lock.unlock();
201 }
202 }
203
204 /**
205 * Acquires a permit from this semaphore, only if one is available at the
206 * time of invocation.
207 * <p>Acquires a permit, if one is available and returns immediately,
208 * with the value <tt>true</tt>,
209 * reducing the number of available permits by one.
210 *
211 * <p>If no permit is available then this method will return
212 * immediately with the value <tt>false</tt>.
213 *
214 * @return <tt>true</tt> if a permit was acquired and <tt>false</tt>
215 * otherwise.
216 */
217 public boolean tryAcquire() {
218 lock.lock();
219 try {
220 if (count > 0) {
221 --count;
222 return true;
223 }
224 return false;
225 } finally {
226 lock.unlock();
227 }
228 }
229
230 /**
231 * Acquires a permit from this semaphore, if one becomes available
232 * within the given waiting time and the
233 * current thread has not been {@link Thread#interrupt interrupted}.
234 * <p>Acquires a permit, if one is available and returns immediately,
235 * with the value <tt>true</tt>,
236 * reducing the number of available permits by one.
237 * <p>If no permit is available then
238 * the current thread becomes disabled for thread scheduling
239 * purposes and lies dormant until one of three things happens:
240 * <ul>
241 * <li>Some other thread invokes the {@link #release} method for this
242 * semaphore and the current thread happens to be chosen as the
243 * thread to receive the permit; or
244 * <li>Some other thread {@link Thread#interrupt interrupts} the current
245 * thread; or
246 * <li>The specified waiting time elapses.
247 * </ul>
248 * <p>If a permit is acquired then the value <tt>true</tt> is returned.
249 * <p>If the current thread:
250 * <ul>
251 * <li>has its interrupted status set on entry to this method; or
252 * <li>is {@link Thread#interrupt interrupted} while waiting to acquire
253 * a permit,
254 * </ul>
255 * then {@link InterruptedException} is thrown and the current thread's
256 * interrupted status is cleared.
257 * <p>If the specified waiting time elapses then the value <tt>false</tt>
258 * is returned.
259 * If the time is
260 * less than or equal to zero, the method will not wait at all.
261 *
262 * @param timeout the maximum time to wait for a permit
263 * @param unit the time unit of the <tt>timeout</tt> argument.
264 * @return <tt>true</tt> if a permit was acquired and <tt>false</tt>
265 * if the waiting time elapsed before a permit was acquired.
266 *
267 * @throws InterruptedException if the current thread is interrupted
268 *
269 * @see Thread#interrupt
270 *
271 */
272 public boolean tryAcquire(long timeout, TimeUnit unit)
273 throws InterruptedException {
274 lock.lockInterruptibly();
275 long nanos = unit.toNanos(timeout);
276 try {
277 for (;;) {
278 if (count > 0) {
279 --count;
280 return true;
281 }
282 if (nanos <= 0)
283 return false;
284 nanos = available.awaitNanos(nanos);
285 }
286 } catch (InterruptedException ie) {
287 available.signal();
288 throw ie;
289 } finally {
290 lock.unlock();
291 }
292 }
293
294 /**
295 * Releases a permit, returning it to the semaphore.
296 * <p>Releases a permit, increasing the number of available permits
297 * by one.
298 * If any threads are blocking trying to acquire a permit, then one
299 * is selected and given the permit that was just released.
300 * That thread is re-enabled for thread scheduling purposes.
301 * <p>There is no requirement that a thread that releases a permit must
302 * have acquired that permit by calling {@link #acquire}.
303 * Correct usage of a semaphore is established by programming convention
304 * in the application.
305 */
306 public void release() {
307 lock.lock();
308 try {
309 ++count;
310 available.signal();
311 } finally {
312 lock.unlock();
313 }
314 }
315
316
317 /**
318 * Return the current number of permits available in this semaphore.
319 * <p>This method is typically used for debugging and testing purposes.
320 * @return the number of permits available in this semaphore.
321 */
322 public long availablePermits() {
323 lock.lock();
324 try {
325 return count;
326 } finally {
327 lock.unlock();
328 }
329 }
330 }
331
332
333