ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/FairSemaphore.java
Revision: 1.3
Committed: Tue Jun 24 14:34:48 2003 UTC (20 years, 11 months ago) by dl
Branch: MAIN
Changes since 1.2: +2 -1 lines
Log Message:
Added missing javadoc tags; minor reformatting

File Contents

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