ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/Semaphore.java
Revision: 1.6
Committed: Wed Jul 9 23:23:17 2003 UTC (20 years, 11 months ago) by dl
Branch: MAIN
Changes since 1.5: +5 -2 lines
Log Message:
Misc performance tunings

File Contents

# User Rev Content
1 dl 1.2 /*
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 tim 1.1 package java.util.concurrent;
8 dl 1.5 import java.util.concurrent.locks.*;
9 tim 1.1
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     * }
58     * else
59     * return false;
60     * }
61     * }
62     * return false;
63     * }
64     *
65     * }
66     * </pre>
67     * <p>Before obtaining an item each thread must acquire a permit from the
68     * semaphore, guaranteeing that an item is available for use. When the
69     * thread has finished with the item it is returned back to the pool and
70     * a permit is returned to the semaphore, allowing another thread to
71     * acquire that item.
72     * Note that no synchronization lock is held when {@link #acquire} is
73     * called as that would prevent an item from being returned to the pool.
74     * The semaphore encapsulates the synchronization needed to restrict access to
75     * the pool, separately from any synchronization needed to maintain the
76     * consistency of the pool itself.
77     *
78     * <p>A semaphore initialized to one, and which is used such that it only
79     * has at most one permit available, can serve as a mutual exclusion lock.
80     * This is more
81     * commonly known as a <em>binary semaphore</em>, because it only has two
82     * states: one permit available, or zero permits available.
83     * When used in this way, the binary semaphore has the property (unlike many
84     * {@link Lock} implementations, that the &quot;lock&quot; can be released by
85     * a thread other than the owner (as semaphores have no notion of ownership).
86     * This can be useful in some specialised contexts, such as deadlock recovery.
87     *
88     * <p>This class makes no guarantees about the order in which threads
89     * acquire permits. In particular, barging is permitted, that is, a thread
90     * invoking {@link #acquire} can be allocated a permit ahead of a thread
91     * that has been waiting. If you need more deterministic guarantees, consider
92 dl 1.3 * using {@link FairSemaphore}.
93 tim 1.1 *
94     *
95     * @since 1.5
96     * @spec JSR-166
97 dl 1.6 * @revised $Date: 2003/07/08 00:46:35 $
98 dl 1.3 * @editor $Author: dl $
99 dl 1.4 * @author Doug Lea
100 tim 1.1 *
101     */
102 dl 1.2 public class Semaphore implements java.io.Serializable {
103     // todo SerialID
104     // uses default serialization, which happens be fine here.
105    
106     // Fields are package-private to allow the FairSemaphore variant
107     // to access.
108    
109     final ReentrantLock lock;
110     final Condition available;
111     long count;
112 tim 1.1
113 dl 1.4 /**
114     * Package-private constructor used by FairSemaphore
115     * @param permits the initial number of permits available
116     * @param lock the lock to use
117     */
118 dl 1.2 Semaphore(long permits, ReentrantLock lock) {
119     this.count = permits;
120     this.lock = lock;
121     available = lock.newCondition();
122     }
123 tim 1.1
124     /**
125     * Construct a <tt>Semaphore</tt> with the given number of
126     * permits.
127     * @param permits the initial number of permits available
128     */
129     public Semaphore(long permits) {
130 dl 1.2 this(permits, new ReentrantLock());
131 tim 1.1 }
132    
133     /**
134     * Acquires a permit from this semaphore, blocking until one is
135     * available, or the thread is {@link Thread#interrupt interrupted}.
136     *
137     * <p>Acquires a permit, if one is available and returns immediately,
138     * reducing the number of available permits by one.
139     * <p>If no permit is available then the current thread becomes
140     * disabled for thread scheduling purposes and lies dormant until
141     * one of two things happens:
142     * <ul>
143     * <li>Some other thread invokes the {@link #release} method for this
144     * semaphore and the current thread happens to be chosen as the
145     * thread to receive the permit; or
146     * <li>Some other thread {@link Thread#interrupt interrupts} the current
147     * thread.
148     * </ul>
149     *
150     * <p>If the current thread:
151     * <ul>
152     * <li>has its interrupted status set on entry to this method; or
153     * <li>is {@link Thread#interrupt interrupted} while waiting
154     * for a permit,
155     * </ul>
156     * then {@link InterruptedException} is thrown and the current thread's
157     * interrupted status is cleared.
158     *
159     * @throws InterruptedException if the current thread is interrupted
160     *
161     * @see Thread#interrupt
162     */
163 dl 1.2 public void acquire() throws InterruptedException {
164     lock.lockInterruptibly();
165     try {
166 dl 1.4 while (count <= 0)
167     available.await();
168 dl 1.2 --count;
169     }
170     catch (InterruptedException ie) {
171     available.signal();
172     throw ie;
173     }
174     finally {
175     lock.unlock();
176     }
177     }
178 tim 1.1
179     /**
180     * Acquires a permit from this semaphore, blocking until one is
181     * available.
182     *
183     * <p>Acquires a permit, if one is available and returns immediately,
184     * reducing the number of available permits by one.
185     * <p>If no permit is available then the current thread becomes
186     * disabled for thread scheduling purposes and lies dormant until
187     * some other thread invokes the {@link #release} method for this
188     * semaphore and the current thread happens to be chosen as the
189     * thread to receive the permit.
190     *
191     * <p>If the current thread
192     * is {@link Thread#interrupt interrupted} while waiting
193     * for a permit then it will continue to wait, but the time at which
194     * the thread is assigned a permit may change compared to the time it
195     * would have received the permit had no interruption occurred. When the
196     * thread does return from this method its interrupt status will be set.
197     *
198     */
199 dl 1.2 public void acquireUninterruptibly() {
200     lock.lock();
201     try {
202 dl 1.4 while (count <= 0)
203     available.awaitUninterruptibly();
204 dl 1.2 --count;
205     }
206     finally {
207     lock.unlock();
208     }
209     }
210 tim 1.1
211     /**
212     * Acquires a permit from this semaphore, only if one is available at the
213     * time of invocation.
214     * <p>Acquires a permit, if one is available and returns immediately,
215     * with the value <tt>true</tt>,
216     * reducing the number of available permits by one.
217     *
218     * <p>If no permit is available then this method will return
219     * immediately with the value <tt>false</tt>.
220     *
221     * @return <tt>true</tt> if a permit was acquired and <tt>false</tt>
222     * otherwise.
223     */
224     public boolean tryAcquire() {
225 dl 1.2 lock.lock();
226     try {
227     if (count > 0) {
228     --count;
229     return true;
230     }
231     return false;
232     }
233     finally {
234     lock.unlock();
235     }
236 tim 1.1 }
237    
238     /**
239     * Acquires a permit from this semaphore, if one becomes available
240     * within the given waiting time and the
241     * current thread has not been {@link Thread#interrupt interrupted}.
242     * <p>Acquires a permit, if one is available and returns immediately,
243     * with the value <tt>true</tt>,
244     * reducing the number of available permits by one.
245     * <p>If no permit is available then
246     * the current thread becomes disabled for thread scheduling
247     * purposes and lies dormant until one of three things happens:
248     * <ul>
249     * <li>Some other thread invokes the {@link #release} method for this
250     * semaphore and the current thread happens to be chosen as the
251     * thread to receive the permit; or
252     * <li>Some other thread {@link Thread#interrupt interrupts} the current
253     * thread; or
254     * <li>The specified waiting time elapses.
255     * </ul>
256     * <p>If a permit is acquired then the value <tt>true</tt> is returned.
257     * <p>If the current thread:
258     * <ul>
259     * <li>has its interrupted status set on entry to this method; or
260     * <li>is {@link Thread#interrupt interrupted} while waiting to acquire
261     * a permit,
262     * </ul>
263     * then {@link InterruptedException} is thrown and the current thread's
264     * interrupted status is cleared.
265     * <p>If the specified waiting time elapses then the value <tt>false</tt>
266     * is returned.
267     * The given waiting time is a best-effort lower bound. If the time is
268     * less than or equal to zero, the method will not wait at all.
269     *
270     * @param timeout the maximum time to wait for a permit
271     * @param granularity the time unit of the <tt>timeout</tt> argument.
272     * @return <tt>true</tt> if a permit was acquired and <tt>false</tt>
273     * if the waiting time elapsed before a permit was acquired.
274     *
275     * @throws InterruptedException if the current thread is interrupted
276     *
277     * @see Thread#interrupt
278     *
279     */
280     public boolean tryAcquire(long timeout, TimeUnit granularity)
281     throws InterruptedException {
282 dl 1.2 lock.lockInterruptibly();
283     long nanos = granularity.toNanos(timeout);
284     try {
285     for (;;) {
286     if (count > 0) {
287     --count;
288     return true;
289     }
290     if (nanos <= 0)
291     return false;
292     nanos = available.awaitNanos(nanos);
293     }
294     }
295     catch (InterruptedException ie) {
296     available.signal();
297     throw ie;
298     }
299     finally {
300     lock.unlock();
301     }
302 tim 1.1 }
303    
304     /**
305     * Releases a permit, returning it to the semaphore.
306     * <p>Releases a permit, increasing the number of available permits
307     * by one.
308     * If any threads are blocking trying to acquire a permit, then one
309     * is selected and given the permit that was just released.
310     * That thread is re-enabled for thread scheduling purposes.
311     * <p>There is no requirement that a thread that releases a permit must
312     * have acquired that permit by calling {@link #acquire}.
313     * Correct usage of a semaphore is established by programming convention
314     * in the application.
315     */
316 dl 1.2 public void release() {
317 dl 1.6 // Even if using fair locks, releases should try to barge in.
318     if (!lock.tryLock())
319     lock.lock();
320    
321 dl 1.2 try {
322     ++count;
323     available.signal();
324     }
325     finally {
326     lock.unlock();
327     }
328     }
329    
330 tim 1.1
331     /**
332     * Return the current number of permits available in this semaphore.
333     * <p>This method is typically used for debugging and testing purposes.
334     * @return the number of permits available in this semaphore.
335     */
336     public long availablePermits() {
337 dl 1.2 lock.lock();
338     try {
339     return count;
340     }
341     finally {
342     lock.unlock();
343     }
344 tim 1.1 }
345     }
346    
347    
348