ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FairSemaphore.java
Revision: 1.1
Committed: Tue May 27 15:50:14 2003 UTC (21 years ago) by dl
Branch: MAIN
CVS Tags: JSR166_PRERELEASE_0_1
Log Message:
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 semaphore that guarantees that threads invoking
11 * any of the {@link #acquire() acquire} methods
12 * are allocated permits in the order in
13 * which their invocation of those methods was processed (first-in-first-out).
14 *
15 * <p>This class introduces a fairness guarantee that can be useful
16 * in some contexts.
17 * However, it needs to be realized that the order in which invocations are
18 * processed can be different from the order in which an application perceives
19 * those invocations to be processed. Effectively, when no permit is available
20 * each thread is stored in a FIFO queue. As permits are released, they
21 * are allocated to the thread at the head of the queue, and so the order
22 * in which threads enter the queue, is the order in which they come out.
23 * This order need not have any relationship to the order in which requests
24 * were made, nor the order in which requests actually return to the caller as
25 * these depend on the underlying thread scheduling, which is not guaranteed
26 * to be predictable or fair.
27 *
28 * <p>As permits are allocated in-order, this class also provides convenience
29 * methods to {@link #acquire(long) acquire} and
30 * {@link #release(long) release} multiple permits at a time.
31 *
32 * @since 1.5
33 * @spec JSR-166
34 * @revised $Date: 2003/01/29 07:08:21 $
35 * @editor $Author: dholmes $
36 *
37 */
38 public class FairSemaphore extends Semaphore {
39
40 /*
41 * This differs from Semaphore only in that it uses a
42 * FairReentrantLock. Because the FairReentrantLock guarantees
43 * FIFO queuing, we don't need to do anything fancy to prevent
44 * overtaking etc. for the multiple-permit methods. The only
45 * minor downside is that multi-permit acquires will sometimes
46 * repeatedly wake up finding that they must re-wait. A custom
47 * solution could minimize this, at the expense of being slower
48 * and more complex for the typical case.
49 */
50
51 /**
52 * Construct a <tt>FiFoSemaphore</tt> with the given number of
53 * permits.
54 * @param permits the initial number of permits available
55 */
56 public FairSemaphore(long permits) {
57 super(permits, new FairReentrantLock());
58 }
59
60 /**
61 * Acquires the given number of permits from this semaphore,
62 * blocking until all are available,
63 * or the thread is {@link Thread#interrupt interrupted}.
64 *
65 * <p>Acquires the given number of permits, if they are available,
66 * and returns immediately,
67 * reducing the number of available permits by the given amount.
68 *
69 * <p>If insufficient permits are available then the current thread becomes
70 * disabled for thread scheduling purposes and lies dormant until
71 * one of two things happens:
72 * <ul>
73 * <li>Some other thread invokes one of the {@link #release() release}
74 * methods for this semaphore, the current thread is next to be assigned
75 * permits and the number of available permits satisfies this request; or
76 * <li>Some other thread {@link Thread#interrupt interrupts} the current
77 * thread.
78 * </ul>
79 *
80 * <p>If the current thread:
81 * <ul>
82 * <li>has its interrupted status set on entry to this method; or
83 * <li>is {@link Thread#interrupt interrupted} while waiting
84 * for a permit,
85 * </ul>
86 * then {@link InterruptedException} is thrown and the current thread's
87 * interrupted status is cleared.
88 * Any available permits are assigned to the next waiting thread as if
89 * they had been made available by a call to {@link #release()}.
90 *
91 * @param permits the number of permits to acquire
92 *
93 * @throws InterruptedException if the current thread is interrupted
94 * @throws IllegalArgumentException if permits less than zero.
95 *
96 * @see Thread#interrupt
97 */
98 public void acquire(long permits) throws InterruptedException {
99 if (permits < 0) throw new IllegalArgumentException();
100
101 lock.lockInterruptibly();
102 try {
103 while (count - permits < 0)
104 available.await();
105 count -= permits;
106 }
107 catch (InterruptedException ie) {
108 available.signal();
109 throw ie;
110 }
111 finally {
112 lock.unlock();
113 }
114
115 }
116
117 /**
118 * Acquires the given number of permits from this semaphore,
119 * blocking until all are available.
120 *
121 * <p>Acquires the given number of permits, if they are available,
122 * and returns immediately,
123 * reducing the number of available permits by the given amount.
124 *
125 * <p>If insufficient permits are available then the current thread becomes
126 * disabled for thread scheduling purposes and lies dormant until
127 * some other thread invokes one of the {@link #release() release}
128 * methods for this semaphore, the current thread is next to be assigned
129 * permits and the number of available permits satisfies this request.
130 *
131 * <p>If the current thread
132 * is {@link Thread#interrupt interrupted} while waiting
133 * for permits then it will continue to wait and its position in the
134 * queue is not affected. When the
135 * thread does return from this method its interrupt status will be set.
136 *
137 * @param permits the number of permits to acquire
138 * @throws IllegalArgumentException if permits less than zero.
139 *
140 */
141 public void acquireUninterruptibly(long permits) {
142 if (permits < 0) throw new IllegalArgumentException();
143
144 lock.lock();
145 try {
146 while (count - permits < 0)
147 available.awaitUninterruptibly();
148 count -= permits;
149 }
150 finally {
151 lock.unlock();
152 }
153 }
154
155 /**
156 * Acquires the given number of permits from this semaphore, only if
157 * all are available at the time of invocation.
158 * <p>Acquires the given number of permits, if they are available, and
159 * returns immediately, with the value <tt>true</tt>,
160 * reducing the number of available permits by the given amount.
161 *
162 * <p>If insufficient permits are available then this method will return
163 * immediately with the value <tt>false</tt> and the number of available
164 * permits is unchanged.
165 *
166 * @param permits the number of permits to acquire
167 *
168 * @return <tt>true</tt> if the permits were acquired and <tt>false</tt>
169 * otherwise.
170 * @throws IllegalArgumentException if permits less than zero.
171 */
172 public boolean tryAcquire(long permits) {
173 if (permits < 0) throw new IllegalArgumentException();
174
175 lock.lock();
176 try {
177 if (count - permits >= 0) {
178 count -= permits;
179 return true;
180 }
181 return false;
182 }
183 finally {
184 lock.unlock();
185 }
186 }
187
188 /**
189 * Acquires the given number of permits from this semaphore, if all
190 * become available within the given waiting time and the
191 * current thread has not been {@link Thread#interrupt interrupted}.
192 * <p>Acquires the given number of permits, if they are available and
193 * returns immediately, with the value <tt>true</tt>,
194 * reducing the number of available permits by the given amount.
195 * <p>If insufficient permits are available then
196 * the current thread becomes disabled for thread scheduling
197 * purposes and lies dormant until one of three things happens:
198 * <ul>
199 * <li>Some other thread invokes one of the {@link #release() release}
200 * methods for this semaphore, the current thread is next to be assigned
201 * permits and the number of available permits satisfies this request; or
202 * <li>Some other thread {@link Thread#interrupt interrupts} the current
203 * thread; or
204 * <li>The specified waiting time elapses.
205 * </ul>
206 * <p>If the permits are acquired then the value <tt>true</tt> is returned.
207 * <p>If the current thread:
208 * <ul>
209 * <li>has its interrupted status set on entry to this method; or
210 * <li>is {@link Thread#interrupt interrupted} while waiting to acquire
211 * the permits,
212 * </ul>
213 * then {@link InterruptedException} is thrown and the current thread's
214 * interrupted status is cleared.
215 * Any available permits are assigned to the next waiting thread as if
216 * they had been made available by a call to {@link #release()}.
217 *
218 * <p>If the specified waiting time elapses then the value <tt>false</tt>
219 * is returned.
220 * The given waiting time is a best-effort lower bound. If the time is
221 * less than or equal to zero, the method will not wait at all.
222 * Any available permits are assigned to the next waiting thread as if
223 * they had been made available by a call to {@link #release()}.
224 *
225 * @param permits the number of permits to acquire
226 * @param timeout the maximum time to wait for the permits
227 * @param granularity the time unit of the <tt>timeout</tt> argument.
228 * @return <tt>true</tt> if all permits were acquired and <tt>false</tt>
229 * if the waiting time elapsed before all permits were acquired.
230 *
231 * @throws InterruptedException if the current thread is interrupted
232 * @throws IllegalArgumentException if permits less than zero.
233 *
234 * @see Thread#interrupt
235 *
236 */
237 public boolean tryAcquire(long permits, long timeout, TimeUnit granularity)
238 throws InterruptedException {
239 if (permits < 0) throw new IllegalArgumentException();
240 lock.lockInterruptibly();
241 long nanos = granularity.toNanos(timeout);
242 try {
243 for (;;) {
244 if (count - permits >= 0) {
245 count -= permits;
246 return true;
247 }
248 if (nanos <= 0)
249 return false;
250 nanos = available.awaitNanos(nanos);
251 }
252 }
253 catch (InterruptedException ie) {
254 available.signal();
255 throw ie;
256 }
257 finally {
258 lock.unlock();
259 }
260
261 }
262
263
264
265 /**
266 * Releases the given number of permits, returning them to the semaphore.
267 * <p>Releases the given number of permits, increasing the number of
268 * available permits by that amount.
269 * If any threads are blocking trying to acquire permits, then the
270 * one that has been waiting the longest
271 * is selected and given the permits that were just released.
272 * If the number of available permits satisfies that thread's request
273 * then that thread is re-enabled for thread scheduling purposes; otherwise
274 * the thread continues to wait. If there are still permits available
275 * after the first thread's request has been satisfied, then those permits
276 * are assigned to the next waiting thread. If it is satisfied then it is
277 * re-enabled for thread scheduling purposes. This continues until there
278 * are insufficient permits to satisfy the next waiting thread, or there
279 * are no more waiting threads.
280 *
281 * <p>There is no requirement that a thread that releases a permit must
282 * have acquired that permit by calling {@link Semaphore#acquire acquire}.
283 * Correct usage of a semaphore is established by programming convention
284 * in the application.
285 *
286 * @param permits the number of permits to release
287 * @throws IllegalArgumentException if permits less than zero.
288 */
289 public void release(long permits) {
290 if (permits < 0) throw new IllegalArgumentException();
291 lock.lock();
292 try {
293 count += permits;
294 for (int i = 0; i < permits; ++i)
295 available.signal();
296 }
297 finally {
298 lock.unlock();
299 }
300 }
301
302
303
304 }
305
306
307
308
309