ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/Semaphore.java
(Generate patch)

Comparing jsr166/src/main/java/util/concurrent/Semaphore.java (file contents):
Revision 1.15 by dl, Sat Nov 1 18:36:04 2003 UTC vs.
Revision 1.16 by dl, Mon Nov 3 13:49:56 2003 UTC

# Line 5 | Line 5
5   */
6  
7   package java.util.concurrent;
8 + import java.util.*;
9   import java.util.concurrent.locks.*;
10 + import java.util.concurrent.atomic.*;
11  
12   /**
13   * A counting semaphore.  Conceptually, a semaphore maintains a set of
# Line 15 | Line 17 | import java.util.concurrent.locks.*;
17   * However, no actual permit objects are used; the <tt>Semaphore</tt> just
18   * keeps a count of the number available and acts accordingly.
19   *
20 < * <p>Semaphores are used to restrict the number of threads than can
20 > * <p>Semaphores are often used to restrict the number of threads than can
21   * access some (physical or logical) resource. For example, here is
22   * a class that uses a semaphore to control access to a pool of items:
23   * <pre>
24   * class Pool {
25   *   private static final MAX_AVAILABLE = 100;
26 < *   private final Semaphore available = new Semaphore(MAX_AVAILABLE);
26 > *   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);
27   *
28   *   public Object getItem() throws InterruptedException {
29   *     available.acquire();
# Line 63 | Line 65 | import java.util.concurrent.locks.*;
65   *
66   * }
67   * </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}.
68   *
69 + * <p>Before obtaining an item each thread must acquire a permit from
70 + * the semaphore, guaranteeing that an item is available for use. When
71 + * the thread has finished with the item it is returned back to the
72 + * pool and a permit is returned to the semaphore, allowing another
73 + * thread to acquire that item.  Note that no synchronization lock is
74 + * held when {@link #acquire} is called as that would prevent an item
75 + * from being returned to the pool.  The semaphore encapsulates the
76 + * synchronization needed to restrict access to the pool, separately
77 + * from any synchronization needed to maintain the consistency of the
78 + * pool itself.
79 + *
80 + * <p>A semaphore initialized to one, and which is used such that it
81 + * only has at most one permit available, can serve as a mutual
82 + * exclusion lock.  This is more commonly known as a <em>binary
83 + * semaphore</em>, because it only has two states: one permit
84 + * available, or zero permits available.  When used in this way, the
85 + * binary semaphore has the property (unlike many {@link Lock}
86 + * implementations, that the &quot;lock&quot; can be released by a
87 + * thread other than the owner (as semaphores have no notion of
88 + * ownership).  This can be useful in some specialized contexts, such
89 + * as deadlock recovery.
90 + *
91 + * <p> The constructor for this class accepts a <em>fairness</em>
92 + * parameter. When set false, this class makes no guarantees about the
93 + * order in which threads acquire permits. In particular, barging is
94 + * permitted, that is, a thread invoking {@link #acquire} can be
95 + * allocated a permit ahead of a thread that has been waiting.  When
96 + * fairness is set true, the semaphore guarantees that threads
97 + * invoking any of the {@link #acquire() acquire} methods are
98 + * allocated permits in the order in which their invocation of those
99 + * methods was processed (first-in-first-out; FIFO). Note that FIFO
100 + * ordering necessarily applies to specific internal points of
101 + * execution within these methods.  So, it is possible for one thread
102 + * to invoke <tt>acquire</tt> before another, but reach the ordering
103 + * point after the other, and similarly upon return from the method.
104 + *
105 + * <p>Generally, semaphores used to control resource access should be
106 + * initialized as fair, to ensure that no thread is starved out from
107 + * accessing a resource. When using semaphores for other kinds of
108 + * synchronization control, the throughput advantages of non-fair
109 + * ordering often outweigh fairness considerations.
110 + *
111 + * <p>This class also provides convenience methods to {@link
112 + * #acquire(int) acquire} and {@link #release(int) release} multiple
113 + * permits at a time.  Beware of the increased risk of indefinite
114 + * postponement when these methods are used without fairness set true,
115   *
116   * @since 1.5
117   * @author Doug Lea
118   *
119   */
120 +
121   public class Semaphore implements java.io.Serializable {
122 <    private static final long serialVersionUID = 3217036696412297181L;
122 >    /*
123 >     * The underlying algorithm here is a simplified adaptation of
124 >     * that used for ReentrantLock. See the internal documentation of
125 >     * ReentrantLock for detailed explanation.
126 >     */
127 >
128 >    private static final long serialVersionUID = -3222578661600680210L;
129  
130 +    /** Node status value to indicate thread has cancelled */
131 +    private static final int CANCELLED =  1;
132 +    /** Node status value to indicate successor needs unparking */
133 +    private static final int SIGNAL    = -1;
134 +    /** Node class for waiting threads */
135 +    private static class Node {
136 +        volatile int status;
137 +        volatile Node prev;
138 +        volatile Node next;
139 +        Thread thread;
140 +        Node(Thread t) { thread = t; }
141 +    }
142  
143 <    // Fields are package-private to allow the FairSemaphore variant
144 <    // to access.
143 >    /** Number of available permits held in a separate AtomicInteger */
144 >    private final AtomicInteger perms;
145 >    /**  Head of the wait queue, lazily initialized.  */
146 >    private transient volatile Node head;
147 >    /**  Tail of the wait queue, lazily initialized.  */
148 >    private transient volatile Node tail;
149 >    /** true if barging disabled */
150 >    private final boolean fair;
151 >
152 >    // Atomic update support
153 >
154 >    private static final
155 >        AtomicReferenceFieldUpdater<Semaphore, Node> tailUpdater =
156 >        AtomicReferenceFieldUpdater.<Semaphore, Node>newUpdater
157 >        (Semaphore.class, Node.class, "tail");
158 >    private static final
159 >        AtomicReferenceFieldUpdater<Semaphore, Node> headUpdater =
160 >        AtomicReferenceFieldUpdater.<Semaphore, Node>newUpdater
161 >        (Semaphore.class,  Node.class, "head");
162 >    private static final
163 >        AtomicIntegerFieldUpdater<Node> statusUpdater =
164 >        AtomicIntegerFieldUpdater.<Node>newUpdater
165 >        (Node.class, "status");
166  
105    final ReentrantLock lock;
106    final ReentrantLock.ConditionObject available;
107    long count;
167  
168 <    /**
169 <     * Package-private constructor used by FairSemaphore
170 <     * @param permits the initial number of permits available
112 <     * @param lock the lock to use
168 >    /**
169 >     * Insert node into queue, initializing head and tail if necessary.
170 >     * @param node the node to insert
171       */
172 <    Semaphore(long permits, ReentrantLock lock) {
173 <        this.count = permits;
174 <        this.lock = lock;
175 <        available = lock.newCondition();
172 >    private void enq(Node node) {
173 >        Node t = tail;
174 >        if (t == null) {         // Must initialize first
175 >            Node h = new Node(null);
176 >            while ((t = tail) == null) {    
177 >                if (headUpdater.compareAndSet(this, null, h))
178 >                    tail = h;
179 >            }
180 >        }
181 >
182 >        for (;;) {
183 >            node.prev = t;      // Prev field must be valid before/upon CAS
184 >            if (tailUpdater.compareAndSet(this, t, node)) {
185 >                t.next = node;  // Next field assignment lags CAS
186 >                return;
187 >            }
188 >            t = tail;
189 >        }
190 >    }
191 >
192 >    /**
193 >     * Unblock the successor of node
194 >     * @param node the node
195 >     */
196 >    private void unparkSuccessor(Node node) {
197 >        statusUpdater.compareAndSet(node, SIGNAL, 0);
198 >        Node s = node.next;
199 >        if (s == null || s.status == CANCELLED) {
200 >            s = tail;
201 >            if (s != null && s != node) {
202 >                Node p = s.prev;
203 >                while (p != null && p != node) {
204 >                    if (p.status != CANCELLED)
205 >                        s = p;
206 >                    p = p.prev;
207 >                }
208 >            }
209 >        }
210 >        if (s != null)
211 >            LockSupport.unpark(s.thread);
212 >    }
213 >
214 >
215 >    /**
216 >     * Internal version of tryAcquire returning number of remaining
217 >     * permits, which is nonnegative only if the acquire succeeded.
218 >     * @param permits requested number of permits
219 >     * @return remaining number of permits
220 >     */
221 >    private int doTryAcquire(int permits) {
222 >        for (;;) {
223 >            int available = perms.get();
224 >            int remaining = available - permits;
225 >            if (remaining < 0 ||
226 >                perms.compareAndSet(available, remaining))
227 >                return remaining;
228 >        }
229 >    }
230 >
231 >    /**
232 >     * Main code for untimed acquires.
233 >     * @param permits number of permits requested
234 >     * @param interrupts interrupt control: -1 for abort on interrupt,
235 >     * 0 for continue on interrupt
236 >     * @return true if lock acquired (can be false only if interruptible)
237 >     */
238 >    private boolean doAcquire(int permits, int interrupts) {
239 >        // Fast path bypasses queue
240 >        if ((!fair || head == tail) && doTryAcquire(permits) >= 0)
241 >            return true;
242 >        Thread current = Thread.currentThread();
243 >        Node node = new Node(current);
244 >        // Retry fast path before enqueuing
245 >        if (!fair && doTryAcquire(permits) >= 0)
246 >            return true;
247 >        enq(node);
248 >
249 >        for (;;) {
250 >            Node p = node.prev;
251 >            if (p == head) {
252 >                int remaining = doTryAcquire(permits);
253 >                if (remaining >= 0) {
254 >                    p.next = null;
255 >                    node.thread = null;
256 >                    node.prev = null;
257 >                    head = node;
258 >                    // if still some permits left, wake up successor
259 >                    if (remaining > 0 && node.status < 0)
260 >                        unparkSuccessor(node);
261 >                    if (interrupts > 0) // Re-interrupt on normal exit
262 >                        current.interrupt();
263 >                    return true;
264 >                }
265 >            }
266 >            int status = p.status;
267 >            if (status == 0)
268 >                statusUpdater.compareAndSet(p, 0, SIGNAL);
269 >            else if (status == CANCELLED)
270 >                node.prev = p.prev;
271 >            else {
272 >                assert (status == SIGNAL);
273 >                LockSupport.park();
274 >                if (Thread.interrupted()) {
275 >                    if (interrupts < 0)  {  
276 >                        node.thread = null;      
277 >                        node.status = CANCELLED;
278 >                        unparkSuccessor(node);
279 >                        return false;
280 >                    }
281 >                    interrupts = 1; // set to re-interrupt on exit
282 >                }
283 >            }
284 >        }
285 >    }
286 >
287 >    /**
288 >     * Main code for timed acquires. Same as doAcquire but with
289 >     * interspersed time checks.
290 >     * @param permits number of permits requested
291 >     * @param nanos timeout in nanosecs
292 >     * @return true if lock acquired
293 >     */
294 >    private boolean doTimedAcquire(int permits, long nanos) throws InterruptedException {
295 >        if ((!fair || head == tail) && doTryAcquire(permits) >= 0)
296 >            return true;
297 >        Thread current = Thread.currentThread();
298 >        long lastTime = System.nanoTime();
299 >        Node node = new Node(current);
300 >        // Retry fast path before enqueuing
301 >        if (!fair && doTryAcquire(permits) >= 0)
302 >            return true;
303 >        enq(node);
304 >
305 >        for (;;) {
306 >            Node p = node.prev;
307 >            if (p == head) {
308 >                int remaining =  doTryAcquire(permits);
309 >                if (remaining >= 0) {
310 >                    p.next = null;
311 >                    node.thread = null;
312 >                    node.prev = null;
313 >                    head = node;
314 >                    if (remaining > 0 && node.status < 0)
315 >                        unparkSuccessor(node);
316 >                    return true;
317 >                }
318 >            }
319 >            if (nanos <= 0L) {    
320 >                node.thread = null;      
321 >                node.status = CANCELLED;
322 >                unparkSuccessor(node);
323 >                return false;
324 >            }
325 >
326 >            int status = p.status;
327 >            if (status == 0)
328 >                statusUpdater.compareAndSet(p, 0, SIGNAL);
329 >            else if (status == CANCELLED)
330 >                node.prev = p.prev;
331 >            else {                      
332 >                LockSupport.parkNanos(nanos);
333 >                if (Thread.interrupted()) {
334 >                    node.thread = null;      
335 >                    node.status = CANCELLED;
336 >                    unparkSuccessor(node);
337 >                    throw new InterruptedException();
338 >                }
339 >                long now = System.nanoTime();
340 >                nanos -= now - lastTime;
341 >                lastTime = now;
342 >            }
343 >        }
344 >    }
345 >
346 >    /**
347 >     * Internal version of release
348 >     */
349 >    private void doRelease(int permits) {
350 >        for (;;) {
351 >            int p = perms.get();
352 >            if (perms.compareAndSet(p, p + permits)) {
353 >                Node h = head;
354 >                if (h != null  && h.status < 0)
355 >                    unparkSuccessor(h);
356 >                return;
357 >            }
358 >        }
359      }
360  
361      /**
362       * Construct a <tt>Semaphore</tt> with the given number of
363 <     * permits.
364 <     * @param permits the initial number of permits available
363 >     * permits and the given fairness setting
364 >     * @param permits the initial number of permits available. This
365 >     * value may be negative, in which case releases must
366 >     * occur before any acquires will be granted.
367 >     * @param fair true if this semaphore will guarantee first-in
368 >     * first-out granting of permits under contention, else false.
369       */
370 <    public Semaphore(long permits) {
371 <        this(permits, new ReentrantLock());
370 >    public Semaphore(int permits, boolean fair) {
371 >        this.fair = fair;
372 >        perms = new AtomicInteger(permits);
373      }
374  
375      /**
# Line 137 | Line 383 | public class Semaphore implements java.i
383       * one of two things happens:
384       * <ul>
385       * <li>Some other thread invokes the {@link #release} method for this
386 <     * semaphore and the current thread happens to be chosen as the
141 <     * thread to receive the permit; or
386 >     * semaphore and the current thread is next to be assigned a permit; or
387       * <li>Some other thread {@link Thread#interrupt interrupts} the current
388       * thread.
389       * </ul>
# Line 157 | Line 402 | public class Semaphore implements java.i
402       * @see Thread#interrupt
403       */
404      public void acquire() throws InterruptedException {
405 <        lock.lockInterruptibly();
406 <        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 <        }
405 >        if (Thread.interrupted() || !doAcquire(1, -1))
406 >            throw new InterruptedException();
407      }
408  
409      /**
# Line 179 | Line 415 | public class Semaphore implements java.i
415       * <p>If no permit is available then the current thread becomes
416       * disabled for thread scheduling purposes and lies dormant until
417       * some other thread invokes the {@link #release} method for this
418 <     * semaphore and the current thread happens to be chosen as the
183 <     * thread to receive the permit.
418 >     * semaphore and the current thread is next to be assigned a permit.
419       *
420       * <p>If the current thread
421       * is {@link Thread#interrupt interrupted} while waiting
# Line 191 | Line 426 | public class Semaphore implements java.i
426       *
427       */
428      public void acquireUninterruptibly() {
429 <        lock.lock();
195 <        try {
196 <            while (count <= 0)
197 <                available.awaitUninterruptibly();
198 <            --count;
199 <        } finally {
200 <            lock.unlock();
201 <        }
429 >        doAcquire(1, 0);
430      }
431  
432      /**
# Line 215 | Line 443 | public class Semaphore implements java.i
443       * otherwise.
444       */
445      public boolean tryAcquire() {
446 <        lock.lock();
219 <        try {
220 <            if (count > 0) {
221 <                --count;
222 <                return true;
223 <            }
224 <            return false;
225 <        } finally {
226 <            lock.unlock();
227 <        }
446 >        return doTryAcquire(1) >= 0;
447      }
448  
449      /**
# Line 239 | Line 458 | public class Semaphore implements java.i
458       * purposes and lies dormant until one of three things happens:
459       * <ul>
460       * <li>Some other thread invokes the {@link #release} method for this
461 <     * semaphore and the current thread happens to be chosen as the
243 <     * thread to receive the permit; or
461 >     * semaphore and the current thread is next to be assigned a permit; or
462       * <li>Some other thread {@link Thread#interrupt interrupts} the current
463       * thread; or
464       * <li>The specified waiting time elapses.
# Line 256 | Line 474 | public class Semaphore implements java.i
474       * interrupted status is cleared.
475       * <p>If the specified waiting time elapses then the value <tt>false</tt>
476       * is returned.
477 <     * If the time is
478 <     * less than or equal to zero, the method will not wait at all.
477 >     * If the time is less than or equal to zero, the method will not wait
478 >     * at all.
479       *
480       * @param timeout the maximum time to wait for a permit
481       * @param unit the time unit of the <tt>timeout</tt> argument.
# Line 269 | Line 487 | public class Semaphore implements java.i
487       * @see Thread#interrupt
488       *
489       */
490 <    public boolean tryAcquire(long timeout, TimeUnit unit)
490 >    public boolean tryAcquire(long timeout, TimeUnit unit)
491          throws InterruptedException {
492 <        lock.lockInterruptibly();
493 <        long nanos = unit.toNanos(timeout);
494 <        try {
495 <            for (;;) {
496 <                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 <        }
492 >        if (unit == null)
493 >            throw new NullPointerException();
494 >        if (Thread.interrupted())
495 >            throw new InterruptedException();
496 >        return doTimedAcquire(1, unit.toNanos(timeout));
497      }
498  
499      /**
# Line 304 | Line 509 | public class Semaphore implements java.i
509       * in the application.
510       */
511      public void release() {
512 <        lock.lock();
513 <        try {
514 <            ++count;
515 <            available.signal();
516 <        } finally {
517 <            lock.unlock();
518 <        }
512 >        doRelease(1);
513 >    }
514 >      
515 >    /**
516 >     * Acquires the given number of permits from this semaphore,
517 >     * blocking until all are available,
518 >     * or the thread is {@link Thread#interrupt interrupted}.
519 >     *
520 >     * <p>Acquires the given number of permits, if they are available,
521 >     * and returns immediately,
522 >     * reducing the number of available permits by the given amount.
523 >     *
524 >     * <p>If insufficient permits are available then the current thread becomes
525 >     * disabled for thread scheduling purposes and lies dormant until
526 >     * one of two things happens:
527 >     * <ul>
528 >     * <li>Some other thread invokes one of the {@link #release() release}
529 >     * methods for this semaphore, the current thread is next to be assigned
530 >     * permits and the number of available permits satisfies this request; or
531 >     * <li>Some other thread {@link Thread#interrupt interrupts} the current
532 >     * thread.
533 >     * </ul>
534 >     *
535 >     * <p>If the current thread:
536 >     * <ul>
537 >     * <li>has its interrupted status set on entry to this method; or
538 >     * <li>is {@link Thread#interrupt interrupted} while waiting
539 >     * for a permit,
540 >     * </ul>
541 >     * then {@link InterruptedException} is thrown and the current thread's
542 >     * interrupted status is cleared.
543 >     * Any permits that were to be assigned to this thread, are instead
544 >     * assigned to the next waiting thread(s), as if
545 >     * they had been made available by a call to {@link #release()}.
546 >     *
547 >     * @param permits the number of permits to acquire
548 >     *
549 >     * @throws InterruptedException if the current thread is interrupted
550 >     * @throws IllegalArgumentException if permits less than zero.
551 >     *
552 >     * @see Thread#interrupt
553 >     */
554 >    public void acquire(int permits) throws InterruptedException {
555 >        if (permits < 0) throw new IllegalArgumentException();
556 >        if (Thread.interrupted() || !doAcquire(permits, -1))
557 >            throw new InterruptedException();
558 >    }
559 >
560 >    /**
561 >     * Acquires the given number of permits from this semaphore,
562 >     * blocking until all are available.
563 >     *
564 >     * <p>Acquires the given number of permits, if they are available,
565 >     * and returns immediately,
566 >     * reducing the number of available permits by the given amount.
567 >     *
568 >     * <p>If insufficient permits are available then the current thread becomes
569 >     * disabled for thread scheduling purposes and lies dormant until
570 >     * some other thread invokes one of the {@link #release() release}
571 >     * methods for this semaphore, the current thread is next to be assigned
572 >     * permits and the number of available permits satisfies this request.
573 >     *
574 >     * <p>If the current thread
575 >     * is {@link Thread#interrupt interrupted} while waiting
576 >     * for permits then it will continue to wait and its position in the
577 >     * queue is not affected. When the
578 >     * thread does return from this method its interrupt status will be set.
579 >     *
580 >     * @param permits the number of permits to acquire
581 >     * @throws IllegalArgumentException if permits less than zero.
582 >     *
583 >     */
584 >    public void acquireUninterruptibly(int permits) {
585 >        if (permits < 0) throw new IllegalArgumentException();
586 >        doAcquire(permits, 0);
587 >    }
588 >
589 >    /**
590 >     * Acquires the given number of permits from this semaphore, only if
591 >     * all are available at the  time of invocation.
592 >     * <p>Acquires the given number of permits, if they are available, and
593 >     * returns immediately, with the value <tt>true</tt>,
594 >     * reducing the number of available permits by the given amount.
595 >     *
596 >     * <p>If insufficient permits are available then this method will return
597 >     * immediately with the value <tt>false</tt> and the number of available
598 >     * permits is unchanged.
599 >     *
600 >     * @param permits the number of permits to acquire
601 >     *
602 >     * @return <tt>true</tt> if the permits were acquired and <tt>false</tt>
603 >     * otherwise.
604 >     * @throws IllegalArgumentException if permits less than zero.
605 >     */
606 >    public boolean tryAcquire(int permits) {
607 >        if (permits < 0) throw new IllegalArgumentException();
608 >        return doTryAcquire(permits) >= 0;
609 >    }
610 >
611 >    /**
612 >     * Acquires the given number of permits from this semaphore, if all
613 >     * become available within the given waiting time and the
614 >     * current thread has not been {@link Thread#interrupt interrupted}.
615 >     * <p>Acquires the given number of permits, if they are available and
616 >     * returns immediately, with the value <tt>true</tt>,
617 >     * reducing the number of available permits by the given amount.
618 >     * <p>If insufficient permits are available then
619 >     * the current thread becomes disabled for thread scheduling
620 >     * purposes and lies dormant until one of three things happens:
621 >     * <ul>
622 >     * <li>Some other thread invokes one of the {@link #release() release}
623 >     * methods for this semaphore, the current thread is next to be assigned
624 >     * permits and the number of available permits satisfies this request; or
625 >     * <li>Some other thread {@link Thread#interrupt interrupts} the current
626 >     * thread; or
627 >     * <li>The specified waiting time elapses.
628 >     * </ul>
629 >     * <p>If the permits are acquired then the value <tt>true</tt> is returned.
630 >     * <p>If the current thread:
631 >     * <ul>
632 >     * <li>has its interrupted status set on entry to this method; or
633 >     * <li>is {@link Thread#interrupt interrupted} while waiting to acquire
634 >     * the permits,
635 >     * </ul>
636 >     * then {@link InterruptedException} is thrown and the current thread's
637 >     * interrupted status is cleared.
638 >     * Any permits that were to be assigned to this thread, are instead
639 >     * assigned to the next waiting thread(s), as if
640 >     * they had been made available by a call to {@link #release()}.
641 >     *
642 >     * <p>If the specified waiting time elapses then the value <tt>false</tt>
643 >     * is returned.
644 >     * If the time is
645 >     * less than or equal to zero, the method will not wait at all.
646 >     * Any permits that were to be assigned to this thread, are instead
647 >     * assigned to the next waiting thread(s), as if
648 >     * they had been made available by a call to {@link #release()}.
649 >     *
650 >     * @param permits the number of permits to acquire
651 >     * @param timeout the maximum time to wait for the permits
652 >     * @param unit the time unit of the <tt>timeout</tt> argument.
653 >     * @return <tt>true</tt> if all permits were acquired and <tt>false</tt>
654 >     * if the waiting time elapsed before all permits were acquired.
655 >     *
656 >     * @throws InterruptedException if the current thread is interrupted
657 >     * @throws IllegalArgumentException if permits less than zero.
658 >     *
659 >     * @see Thread#interrupt
660 >     *
661 >     */
662 >    public boolean tryAcquire(int permits, long timeout, TimeUnit unit)
663 >        throws InterruptedException {
664 >        if (permits < 0) throw new IllegalArgumentException();
665 >        if (unit == null)
666 >            throw new NullPointerException();
667 >        if (Thread.interrupted())
668 >            throw new InterruptedException();
669 >        return doTimedAcquire(permits, unit.toNanos(timeout));
670 >    }
671 >
672 >
673 >    /**
674 >     * Releases the given number of permits, returning them to the semaphore.
675 >     * <p>Releases the given number of permits, increasing the number of
676 >     * available permits by that amount.
677 >     * If any threads are blocking trying to acquire permits, then the
678 >     * one that has been waiting the intest
679 >     * is selected and given the permits that were just released.
680 >     * If the number of available permits satisfies that thread's request
681 >     * then that thread is re-enabled for thread scheduling purposes; otherwise
682 >     * the thread continues to wait. If there are still permits available
683 >     * after the first thread's request has been satisfied, then those permits
684 >     * are assigned to the next waiting thread. If it is satisfied then it is
685 >     * re-enabled for thread scheduling purposes. This continues until there
686 >     * are insufficient permits to satisfy the next waiting thread, or there
687 >     * are no more waiting threads.
688 >     *
689 >     * <p>There is no requirement that a thread that releases a permit must
690 >     * have acquired that permit by calling {@link Semaphore#acquire acquire}.
691 >     * Correct usage of a semaphore is established by programming convention
692 >     * in the application.
693 >     *
694 >     * @param permits the number of permits to release
695 >     * @throws IllegalArgumentException if permits less than zero.
696 >     */
697 >    public void release(int permits) {
698 >        if (permits < 0) throw new IllegalArgumentException();
699 >        doRelease(permits);
700      }
315        
701  
702      /**
703       * Return the current number of permits available in this semaphore.
704       * <p>This method is typically used for debugging and testing purposes.
705       * @return the number of permits available in this semaphore.
706       */
707 <    public long availablePermits() {
708 <        lock.lock();
324 <        try {
325 <            return count;
326 <        } finally {
327 <            lock.unlock();
328 <        }
707 >    public int availablePermits() {
708 >        return perms.get();
709      }
710  
711      /**
# Line 338 | Line 718 | public class Semaphore implements java.i
718       * @param reduction the number of permits to remove
719       * @throws IllegalArgumentException if reduction is negative
720       */
721 <    protected void reducePermits(long reduction) {
721 >    protected void reducePermits(int reduction) {
722          if (reduction < 0) throw new IllegalArgumentException();
723 <        lock.lock();
724 <        try {
725 <            count -= reduction;
726 <        } finally {
727 <            lock.unlock();
728 <        }
723 >        perms.getAndAdd(-reduction);
724 >    }
725 >
726 >    /**
727 >     * Return true if this semaphore has fairness set true.
728 >     * @return true if this semaphore has fairness set true.
729 >     */
730 >    public boolean isFair() {
731 >        return fair;
732      }
733 +
734 +    /**
735 +     * Returns an estimate of the number of threads waiting to acquire
736 +     * a permit. The value is only an estimate because the number of
737 +     * threads may change dynamically while this method traverses
738 +     * internal data structures.  This method is designed for use in
739 +     * monitoring of the system state, not for synchronization
740 +     * control.
741 +     * @return the estimated number of threads waiting for a permit
742 +     */
743 +    public int getQueueLength() {
744 +        int n = 0;
745 +        for (Node p = tail; p != null && p != head; p = p.prev)
746 +            ++n;
747 +        return n;
748 +    }
749 +
750 +    /**
751 +     * Returns a collection containing threads that may be waiting to
752 +     * acquire a permit.  Because the actual set of threads may
753 +     * change dynamically while constructing this result, the returned
754 +     * collection is only a best-effort estimate.  The elements of the
755 +     * returned collection are in no particular order.  This method is
756 +     * designed to facilitate construction of subclasses that provide
757 +     * more extensive monitoring facilities.
758 +     * @return the collection of threads
759 +     */
760 +    protected Collection<Thread> getQueuedThreads() {
761 +        ArrayList<Thread> list = new ArrayList<Thread>();
762 +        for (Node p = tail; p != null; p = p.prev) {
763 +            Thread t = p.thread;
764 +            if (t != null)
765 +                list.add(t);
766 +        }
767 +        return list;
768 +    }
769 +
770   }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines