001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: /*
020: * Written by Doug Lea with assistance from members of JCP JSR-166
021: * Expert Group and released to the public domain, as explained at
022: * http://creativecommons.org/licenses/publicdomain
023: */
024: package org.apache.openjpa.lib.util.concurrent;
025:
026: import java.util.Collection;
027:
028: /**
029: * A reentrant mutual exclusion {@link Lock} with the same basic
030: * behavior and semantics as the implicit monitor lock accessed using
031: * <tt>synchronized</tt> methods and statements, but with extended capabilities.
032: * A <tt>ReentrantLock</tt> is <em>owned</em> by the thread last
033: * successfully locking, but not yet unlocking it. A thread invoking
034: * <tt>lock</tt> will return, successfully acquiring the lock, when
035: * the lock is not owned by another thread. The method will return
036: * immediately if the current thread already owns the lock. This can
037: * be checked using methods {@link #isHeldByCurrentThread}, and {@link
038: * #getHoldCount}. The constructor for this class accepts an optional
039: * <em>fairness</em> parameter. When set <tt>true</tt>, under
040: * contention, locks favor granting access to the longest-waiting
041: * thread. Otherwise this lock does not guarantee any particular
042: * access order. Programs using fair locks accessed by many threads
043: * may display lower overall throughput(i.e., are slower; often much
044: * slower) than those using the default setting, but have smaller
045: * variances in times to obtain locks and guarantee lack of
046: * starvation. Note however, that fairness of locks does not guarantee
047: * fairness of thread scheduling. Thus, one of many threads using a
048: * fair lock may obtain it multiple times in succession while other
049: * active threads are not progressing and not currently holding the lock.
050: * Also note that the untimed {@link #tryLock() tryLock} method does not
051: * honor the fairness setting. It will succeed if the lock
052: * is available even if other threads are waiting.
053: * It is recommended practice to <em>always</em> immediately
054: * follow a call to <tt>lock</tt> with a <tt>try</tt> block, most
055: * typically in a before/after construction such as:
056: *
057: * <pre> class X { private final ReentrantLock lock = new ReentrantLock();
058: * // ... public void m() { lock.lock(); // block until condition holds try {
059: * // ... method body } finally { lock.unlock() } } }
060: * </pre> In addition to implementing the {@link Lock} interface, this
061: * class defines methods <tt>isLocked</tt> and
062: * <tt>getLockQueueLength</tt>, as well as some associated
063: * <tt>protected</tt> access methods that may be useful for
064: * instrumentation and monitoring.
065: * Serialization of this class behaves in the same way as built-in
066: * locks: a deserialized lock is in the unlocked state, regardless of
067: * its state when serialized.
068: * This lock supports a maximum of 2147483647 recursive locks by
069: * the same thread. Attempts to exceed this limit result in
070: * {@link Error} throws from locking methods.
071: *
072: * @author Doug Lea
073: * @author Dawid Kurzyniec
074: * @since 1.5
075: */
076: public class ReentrantLock implements Lock, java.io.Serializable,
077: CondVar.ExclusiveLock {
078:
079: private static final long serialVersionUID = 7373984872572414699L;
080:
081: private final Sync sync;
082:
083: static abstract class Sync implements java.io.Serializable {
084:
085: private static final long serialVersionUID = -5179523762034025860L;
086:
087: protected transient Thread owner_ = null;
088: protected transient int holds_ = 0;
089:
090: protected Sync() {
091: }
092:
093: public abstract void lock();
094:
095: public abstract void lockInterruptibly()
096: throws InterruptedException;
097:
098: final void incHolds() {
099: int nextHolds = ++holds_;
100: if (nextHolds < 0)
101: throw new Error("Maximum lock count exceeded");
102: holds_ = nextHolds;
103: }
104:
105: public boolean tryLock() {
106: Thread caller = Thread.currentThread();
107: synchronized (this ) {
108: if (owner_ == null) {
109: owner_ = caller;
110: holds_ = 1;
111: return true;
112: } else if (caller == owner_) {
113: incHolds();
114: return true;
115: }
116: }
117: return false;
118: }
119:
120: public abstract boolean tryLock(long nanos)
121: throws InterruptedException;
122:
123: public abstract void unlock();
124:
125: public synchronized int getHoldCount() {
126: return isHeldByCurrentThread() ? holds_ : 0;
127: }
128:
129: public synchronized boolean isHeldByCurrentThread() {
130: return holds_ > 0 && Thread.currentThread() == owner_;
131: }
132:
133: public synchronized boolean isLocked() {
134: return owner_ != null;
135: }
136:
137: public abstract boolean isFair();
138:
139: protected synchronized Thread getOwner() {
140: return owner_;
141: }
142:
143: public boolean hasQueuedThreads() {
144: throw new UnsupportedOperationException("Use FAIR version");
145: }
146:
147: public int getQueueLength() {
148: throw new UnsupportedOperationException("Use FAIR version");
149: }
150:
151: public Collection getQueuedThreads() {
152: throw new UnsupportedOperationException("Use FAIR version");
153: }
154:
155: public boolean isQueued(Thread thread) {
156: throw new UnsupportedOperationException("Use FAIR version");
157: }
158: }
159:
160: final static class NonfairSync extends Sync {
161:
162: private static final long serialVersionUID = 7316153563782823691L;
163:
164: NonfairSync() {
165: }
166:
167: public void lock() {
168: Thread caller = Thread.currentThread();
169: synchronized (this ) {
170: if (owner_ == null) {
171: owner_ = caller;
172: holds_ = 1;
173: return;
174: } else if (caller == owner_) {
175: incHolds();
176: return;
177: } else {
178: boolean wasInterrupted = Thread.interrupted();
179: try {
180: while (true) {
181: try {
182: wait();
183: } catch (InterruptedException e) {
184: wasInterrupted = true;
185: // no need to notify; if we were signalled, we
186: // will act as signalled, ignoring the
187: // interruption
188: }
189: if (owner_ == null) {
190: owner_ = caller;
191: holds_ = 1;
192: return;
193: }
194: }
195: } finally {
196: if (wasInterrupted)
197: Thread.currentThread().interrupt();
198: }
199: }
200: }
201: }
202:
203: public void lockInterruptibly() throws InterruptedException {
204: if (Thread.interrupted())
205: throw new InterruptedException();
206: Thread caller = Thread.currentThread();
207: synchronized (this ) {
208: if (owner_ == null) {
209: owner_ = caller;
210: holds_ = 1;
211: return;
212: } else if (caller == owner_) {
213: incHolds();
214: return;
215: } else {
216: try {
217: do {
218: wait();
219: } while (owner_ != null);
220: owner_ = caller;
221: holds_ = 1;
222: return;
223: } catch (InterruptedException ex) {
224: if (owner_ == null)
225: notify();
226: throw ex;
227: }
228: }
229: }
230: }
231:
232: public boolean tryLock(long nanos) throws InterruptedException {
233: if (Thread.interrupted())
234: throw new InterruptedException();
235: Thread caller = Thread.currentThread();
236:
237: synchronized (this ) {
238: if (owner_ == null) {
239: owner_ = caller;
240: holds_ = 1;
241: return true;
242: } else if (caller == owner_) {
243: incHolds();
244: return true;
245: } else if (nanos <= 0)
246: return false;
247: else {
248: long deadline = Utils.nanoTime() + nanos;
249: try {
250: for (;;) {
251: TimeUnit.NANOSECONDS.timedWait(this , nanos);
252: if (caller == owner_) {
253: incHolds();
254: return true;
255: } else if (owner_ == null) {
256: owner_ = caller;
257: holds_ = 1;
258: return true;
259: } else {
260: nanos = deadline - Utils.nanoTime();
261: if (nanos <= 0)
262: return false;
263: }
264: }
265: } catch (InterruptedException ex) {
266: if (owner_ == null)
267: notify();
268: throw ex;
269: }
270: }
271: }
272: }
273:
274: public synchronized void unlock() {
275: if (Thread.currentThread() != owner_)
276: throw new IllegalMonitorStateException("Not owner");
277:
278: if (--holds_ == 0) {
279: owner_ = null;
280: notify();
281: }
282: }
283:
284: public final boolean isFair() {
285: return false;
286: }
287: }
288:
289: final static class FairSync extends Sync implements
290: WaitQueue.QueuedSync {
291:
292: private static final long serialVersionUID = -3000897897090466540L;
293:
294: private transient WaitQueue wq_ = new FIFOWaitQueue();
295:
296: FairSync() {
297: }
298:
299: public synchronized boolean recheck(WaitQueue.WaitNode node) {
300: Thread caller = Thread.currentThread();
301: if (owner_ == null) {
302: owner_ = caller;
303: holds_ = 1;
304: return true;
305: } else if (caller == owner_) {
306: incHolds();
307: return true;
308: }
309: wq_.insert(node);
310: return false;
311: }
312:
313: public synchronized void takeOver(WaitQueue.WaitNode node) {
314: // assert(holds_ == 1 && owner_ == Thread.currentThread()
315: owner_ = node.getOwner();
316: }
317:
318: public void lock() {
319: Thread caller = Thread.currentThread();
320: synchronized (this ) {
321: if (owner_ == null) {
322: owner_ = caller;
323: holds_ = 1;
324: return;
325: } else if (caller == owner_) {
326: incHolds();
327: return;
328: }
329: }
330: WaitQueue.WaitNode n = new WaitQueue.WaitNode();
331: n.doWaitUninterruptibly(this );
332: }
333:
334: public void lockInterruptibly() throws InterruptedException {
335: if (Thread.interrupted())
336: throw new InterruptedException();
337: Thread caller = Thread.currentThread();
338: synchronized (this ) {
339: if (owner_ == null) {
340: owner_ = caller;
341: holds_ = 1;
342: return;
343: } else if (caller == owner_) {
344: incHolds();
345: return;
346: }
347: }
348: WaitQueue.WaitNode n = new WaitQueue.WaitNode();
349: n.doWait(this );
350: }
351:
352: public boolean tryLock(long nanos) throws InterruptedException {
353: if (Thread.interrupted())
354: throw new InterruptedException();
355: Thread caller = Thread.currentThread();
356: synchronized (this ) {
357: if (owner_ == null) {
358: owner_ = caller;
359: holds_ = 1;
360: return true;
361: } else if (caller == owner_) {
362: incHolds();
363: return true;
364: }
365: }
366: WaitQueue.WaitNode n = new WaitQueue.WaitNode();
367: return n.doTimedWait(this , nanos);
368: }
369:
370: protected synchronized WaitQueue.WaitNode getSignallee(
371: Thread caller) {
372: if (caller != owner_)
373: throw new IllegalMonitorStateException("Not owner");
374: // assert(holds_ > 0)
375: if (holds_ >= 2) { // current thread will keep the lock
376: --holds_;
377: return null;
378: }
379: // assert(holds_ == 1)
380: WaitQueue.WaitNode w = wq_.extract();
381: if (w == null) { // if none, clear for new arrivals
382: owner_ = null;
383: holds_ = 0;
384: }
385: return w;
386: }
387:
388: public void unlock() {
389: Thread caller = Thread.currentThread();
390: for (;;) {
391: WaitQueue.WaitNode w = getSignallee(caller);
392: if (w == null)
393: return; // no one to signal
394: if (w.signal(this ))
395: return; // notify if still waiting, or skip
396: }
397: }
398:
399: public final boolean isFair() {
400: return true;
401: }
402:
403: public synchronized boolean hasQueuedThreads() {
404: return wq_.hasNodes();
405: }
406:
407: public synchronized int getQueueLength() {
408: return wq_.getLength();
409: }
410:
411: public synchronized Collection getQueuedThreads() {
412: return wq_.getWaitingThreads();
413: }
414:
415: public synchronized boolean isQueued(Thread thread) {
416: return wq_.isWaiting(thread);
417: }
418:
419: private void readObject(java.io.ObjectInputStream in)
420: throws java.io.IOException, ClassNotFoundException {
421: in.defaultReadObject();
422: synchronized (this ) {
423: wq_ = new FIFOWaitQueue();
424: }
425: }
426: }
427:
428: /**
429: * Creates an instance of <tt>ReentrantLock</tt>.
430: * This is equivalent to using <tt>ReentrantLock(false)</tt>.
431: */
432: public ReentrantLock() {
433: sync = new NonfairSync();
434: }
435:
436: /**
437: * Creates an instance of <tt>ReentrantLock</tt> with the
438: * given fairness policy.
439: *
440: * @param fair true if this lock will be fair; else false
441: */
442: public ReentrantLock(boolean fair) {
443: sync = (fair) ? (Sync) new FairSync() : new NonfairSync();
444: }
445:
446: /**
447: * Acquires the lock.
448: * Acquires the lock if it is not held by another thread and returns
449: * immediately, setting the lock hold count to one. If the current thread
450: * already holds the lock then the hold count is incremented by one and
451: * the method returns immediately.
452: * If the lock is held by another thread then the
453: * current thread becomes disabled for thread scheduling
454: * purposes and lies dormant until the lock has been acquired,
455: * at which time the lock hold count is set to one.
456: */
457: public void lock() {
458: sync.lock();
459: }
460:
461: /**
462: * Acquires the lock unless the current thread is
463: * {@link Thread#interrupt interrupted}.
464: * Acquires the lock if it is not held by another thread and returns
465: * immediately, setting the lock hold count to one.
466: * If the current thread already holds this lock then the hold count
467: * is incremented by one and the method returns immediately.
468: * If the lock is held by another thread then the
469: * current thread becomes disabled for thread scheduling
470: * purposes and lies dormant until one of two things happens:
471: *
472: * <ul>
473: *
474: * <li>The lock is acquired by the current thread; or
475: *
476: * <li>Some other thread {@link Thread#interrupt interrupts} the current
477: * thread.
478: *
479: * </ul> If the lock is acquired by the current thread then the lock hold
480: * count is set to one. If the current thread:
481: *
482: * <ul>
483: *
484: * <li>has its interrupted status set on entry to this method; or
485: *
486: * <li>is {@link Thread#interrupt interrupted} while acquiring the lock,
487: *
488: * </ul>
489: * then {@link InterruptedException} is thrown and the current thread's
490: * interrupted status is cleared.
491: * In this implementation, as this method is an explicit interruption
492: * point, preference is
493: * given to responding to the interrupt over normal or reentrant
494: * acquisition of the lock.
495: *
496: * @throws InterruptedException if the current thread is interrupted
497: */
498: public void lockInterruptibly() throws InterruptedException {
499: sync.lockInterruptibly();
500: }
501:
502: /**
503: * Acquires the lock only if it is not held by another thread at the time
504: * of invocation. Acquires the lock if it is not held by another thread and
505: * returns immediately with the value <tt>true</tt>, setting the
506: * lock hold count to one. Even when this lock has been set to use a
507: * fair ordering policy, a call to <tt>tryLock()</tt> <em>will</em>
508: * immediately acquire the lock if it is available, whether or not
509: * other threads are currently waiting for the lock.
510: * This "barging" behavior can be useful in certain
511: * circumstances, even though it breaks fairness. If you want to honor
512: * the fairness setting for this lock, then use
513: * {@link #tryLock(long, TimeUnit) tryLock(0, TimeUnit.SECONDS) }
514: * which is almost equivalent(it also detects interruption).
515: * If the current thread
516: * already holds this lock then the hold count is incremented by one and
517: * the method returns <tt>true</tt>.
518: * If the lock is held by another thread then this method will return
519: * immediately with the value <tt>false</tt>.
520: *
521: * @return <tt>true</tt> if the lock was free and was acquired by the
522: * current thread, or the lock was already held by the current thread; and
523: * <tt>false</tt> otherwise.
524: */
525: public boolean tryLock() {
526: return sync.tryLock();
527: }
528:
529: /**
530: * Acquires the lock if it is not held by another thread within the given
531: * waiting time and the current thread has not been
532: * {@link Thread#interrupt interrupted}.
533: * Acquires the lock if it is not held by another thread and returns
534: * immediately with the value <tt>true</tt>, setting the lock hold count
535: * to one. If this lock has been set to use a fair ordering policy then
536: * an available lock <em>will not</em> be acquired if any other threads
537: * are waiting for the lock. This is in contrast to the {@link #tryLock()}
538: * method. If you want a timed <tt>tryLock</tt> that does permit barging on
539: * a fair lock then combine the timed and un-timed forms together:
540: *
541: * <pre>if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
542: * </pre> If the current thread
543: * already holds this lock then the hold count is incremented by one and
544: * the method returns <tt>true</tt>.
545: * If the lock is held by another thread then the
546: * current thread becomes disabled for thread scheduling
547: * purposes and lies dormant until one of three things happens:
548: *
549: * <ul>
550: *
551: * <li>The lock is acquired by the current thread; or
552: *
553: * <li>Some other thread {@link Thread#interrupt interrupts} the current
554: * thread; or
555: *
556: * <li>The specified waiting time elapses
557: *
558: * </ul>
559: * If the lock is acquired then the value <tt>true</tt> is returned and
560: * the lock hold count is set to one. If the current thread:
561: *
562: * <ul>
563: *
564: * <li>has its interrupted status set on entry to this method; or
565: *
566: * <li>is {@link Thread#interrupt interrupted} while acquiring the lock,
567: *
568: * </ul>
569: * then {@link InterruptedException} is thrown and the current thread's
570: * interrupted status is cleared.
571: * If the specified waiting time elapses then the value <tt>false</tt>
572: * is returned. If the time is
573: * less than or equal to zero, the method will not wait at all.
574: * In this implementation, as this method is an explicit interruption
575: * point, preference is
576: * given to responding to the interrupt over normal or reentrant
577: * acquisition of the lock, and over reporting the elapse of the waiting
578: * time.
579: *
580: * @param timeout the time to wait for the lock
581: * @param unit the time unit of the timeout argument
582: * @return <tt>true</tt> if the lock was free and was acquired by the
583: * current thread, or the lock was already held by the current thread; and
584: * <tt>false</tt> if the waiting time elapsed before the lock could be
585: * acquired.
586: * @throws InterruptedException if the current thread is interrupted
587: * @throws NullPointerException if unit is null
588: */
589: public boolean tryLock(long timeout, TimeUnit unit)
590: throws InterruptedException {
591: return sync.tryLock(unit.toNanos(timeout));
592: }
593:
594: /**
595: * Attempts to release this lock. If the current thread is the
596: * holder of this lock then the hold count is decremented. If the
597: * hold count is now zero then the lock is released. If the
598: * current thread is not the holder of this lock then {@link
599: * IllegalMonitorStateException} is thrown.
600: *
601: * @throws IllegalMonitorStateException if the current thread does not
602: * hold this lock.
603: */
604: public void unlock() {
605: sync.unlock();
606: }
607:
608: /**
609: * Returns a {@link Condition} instance for use with this
610: * {@link Lock} instance.
611: * The returned {@link Condition} instance supports the same
612: * usages as do the {@link Object} monitor methods({@link
613: * Object#wait() wait}, {@link Object#notify notify}, and {@link
614: * Object#notifyAll notifyAll}) when used with the built-in monitor lock.
615: *
616: * <ul>
617: *
618: * <li>If this lock is not held when any of the {@link Condition}
619: * {@link Condition#await() waiting} or {@link Condition#signal
620: * signalling} methods are called, then an {@link
621: * IllegalMonitorStateException} is thrown.
622: *
623: * <li>When the condition {@link Condition#await() waiting}
624: * methods are called the lock is released and, before they
625: * return, the lock is reacquired and the lock hold count restored
626: * to what it was when the method was called.
627: *
628: * <li>If a thread is {@link Thread#interrupt interrupted} while
629: * waiting then the wait will terminate, an {@link
630: * InterruptedException} will be thrown, and the thread's
631: * interrupted status will be cleared.
632: *
633: * <li> Waiting threads are signalled in FIFO order
634: *
635: * <li>The ordering of lock reacquisition for threads returning
636: * from waiting methods is the same as for threads initially
637: * acquiring the lock, which is in the default case not specified,
638: * but for <em>fair</em> locks favors those threads that have been
639: * waiting the longest.
640: *
641: * </ul>
642: *
643: * @return the Condition object
644: */
645: public Condition newCondition() {
646: return isFair() ? new FIFOCondVar(this ) : new CondVar(this );
647: }
648:
649: /**
650: * Queries the number of holds on this lock by the current thread.
651: * A thread has a hold on a lock for each lock action that is not
652: * matched by an unlock action.
653: * The hold count information is typically only used for testing and
654: * debugging purposes. For example, if a certain section of code should
655: * not be entered with the lock already held then we can assert that fact:
656: *
657: * <pre> class X { ReentrantLock lock = new ReentrantLock(); // ...
658: * public void m() { assert lock.getHoldCount() == 0; lock.lock(); try {
659: * // ... method body } finally { lock.unlock(); } } }
660: * </pre>
661: *
662: * @return the number of holds on this lock by the current thread,
663: * or zero if this lock is not held by the current thread.
664: */
665: public int getHoldCount() {
666: return sync.getHoldCount();
667: }
668:
669: /**
670: * Queries if this lock is held by the current thread.
671: * Analogous to the {@link Thread#holdsLock} method for built-in
672: * monitor locks, this method is typically used for debugging and
673: * testing. For example, a method that should only be called while
674: * a lock is held can assert that this is the case:
675: *
676: * <pre> class X { ReentrantLock lock = new ReentrantLock(); // ...
677: * public void m() { assert lock.isHeldByCurrentThread();
678: * // ... method body } }
679: * </pre> It can also be used to ensure that a reentrant lock is used
680: * in a non-reentrant manner, for example:
681: *
682: * <pre> class X { ReentrantLock lock = new ReentrantLock(); // ...
683: * public void m() { assert !lock.isHeldByCurrentThread(); lock.lock();
684: * try { // ... method body } finally { lock.unlock(); } } }
685: * </pre>
686: *
687: * @return <tt>true</tt> if current thread holds this lock and
688: * <tt>false</tt> otherwise.
689: */
690: public boolean isHeldByCurrentThread() {
691: return sync.isHeldByCurrentThread();
692: }
693:
694: /**
695: * Queries if this lock is held by any thread. This method is
696: * designed for use in monitoring of the system state,
697: * not for synchronization control.
698: *
699: * @return <tt>true</tt> if any thread holds this lock and
700: * <tt>false</tt> otherwise.
701: */
702: public boolean isLocked() {
703: return sync.isLocked();
704: }
705:
706: /**
707: * Returns true if this lock has fairness set true.
708: *
709: * @return true if this lock has fairness set true.
710: */
711: public final boolean isFair() {
712: return sync.isFair();
713: }
714:
715: /**
716: * <tt>null</tt> if not owned. When this method is called by a
717: * thread that is not the owner, the return value reflects a
718: * best-effort approximation of current lock status. For example,
719: * the owner may be momentarily <tt>null</tt> even if there are
720: * threads trying to acquire the lock but have not yet done so.
721: * This method is designed to facilitate construction of
722: * subclasses that provide more extensive lock monitoring facilities.
723: *
724: * @return the owner, or <tt>null</tt> if not owned
725: */
726: protected Thread getOwner() {
727: return sync.getOwner();
728: }
729:
730: /**
731: * Queries whether any threads are waiting to acquire this lock. Note that
732: * because cancellations may occur at any time, a <tt>true</tt>
733: * return does not guarantee that any other thread will ever
734: * acquire this lock. This method is designed primarily for use in
735: * monitoring of the system state.
736: *
737: * @return true if there may be other threads waiting to acquire the lock.
738: */
739: public final boolean hasQueuedThreads() {
740: return sync.hasQueuedThreads();
741: }
742:
743: /**
744: * Queries whether the given thread is waiting to acquire this
745: * lock. Note that because cancellations may occur at any time, a
746: * <tt>true</tt> return does not guarantee that this thread
747: * will ever acquire this lock. This method is designed primarily for use
748: * in monitoring of the system state.
749: *
750: * @param thread the thread
751: * @return true if the given thread is queued waiting for this lock.
752: * @throws NullPointerException if thread is null
753: */
754: public final boolean hasQueuedThread(Thread thread) {
755: return sync.isQueued(thread);
756: }
757:
758: /**
759: * Returns an estimate of the number of threads waiting to
760: * acquire this lock. The value is only an estimate because the number of
761: * threads may change dynamically while this method traverses
762: * internal data structures. This method is designed for use in
763: * monitoring of the system state, not for synchronization control.
764: *
765: * @return the estimated number of threads waiting for this lock
766: */
767: public final int getQueueLength() {
768: return sync.getQueueLength();
769: }
770:
771: /**
772: * Returns a collection containing threads that may be waiting to
773: * acquire this lock. Because the actual set of threads may change
774: * dynamically while constructing this result, the returned
775: * collection is only a best-effort estimate. The elements of the
776: * returned collection are in no particular order. This method is
777: * designed to facilitate construction of subclasses that provide
778: * more extensive monitoring facilities.
779: *
780: * @return the collection of threads
781: */
782: protected Collection getQueuedThreads() {
783: return sync.getQueuedThreads();
784: }
785:
786: /**
787: * Queries whether any threads are waiting on the given condition
788: * associated with this lock. Note that because timeouts and
789: * interrupts may occur at any time, a <tt>true</tt> return does
790: * not guarantee that a future <tt>signal</tt> will awaken any
791: * threads. This method is designed primarily for use in
792: * monitoring of the system state.
793: *
794: * @param condition the condition
795: * @return <tt>true</tt> if there are any waiting threads.
796: * @throws IllegalMonitorStateException if this lock is not held
797: * @throws IllegalArgumentException if the given condition is
798: * not associated with this lock
799: * @throws NullPointerException if condition null
800: */
801: public boolean hasWaiters(Condition condition) {
802: return asCondVar(condition).hasWaiters();
803: }
804:
805: /**
806: * Returns an estimate of the number of threads waiting on the
807: * given condition associated with this lock. Note that because
808: * timeouts and interrupts may occur at any time, the estimate
809: * serves only as an upper bound on the actual number of waiters.
810: * This method is designed for use in monitoring of the system
811: * state, not for synchronization control.
812: *
813: * @param condition the condition
814: * @return the estimated number of waiting threads.
815: * @throws IllegalMonitorStateException if this lock is not held
816: * @throws IllegalArgumentException if the given condition is
817: * not associated with this lock
818: * @throws NullPointerException if condition null
819: */
820: public int getWaitQueueLength(Condition condition) {
821: return asCondVar(condition).getWaitQueueLength();
822: }
823:
824: /**
825: * Returns a collection containing those threads that may be
826: * waiting on the given condition associated with this lock.
827: * Because the actual set of threads may change dynamically while
828: * constructing this result, the returned collection is only a
829: * best-effort estimate. The elements of the returned collection
830: * are in no particular order. This method is designed to
831: * facilitate construction of subclasses that provide more
832: * extensive condition monitoring facilities.
833: *
834: * @param condition the condition
835: * @return the collection of threads
836: * @throws IllegalMonitorStateException if this lock is not held
837: * @throws IllegalArgumentException if the given condition is
838: * not associated with this lock
839: * @throws NullPointerException if condition null
840: */
841: protected Collection getWaitingThreads(Condition condition) {
842: return asCondVar(condition).getWaitingThreads();
843: }
844:
845: /**
846: * Returns a string identifying this lock, as well as its lock
847: * state. The state, in brackets, includes either the String
848: * "Unlocked" or the String "Locked by"
849: * followed by the {@link Thread#getName} of the owning thread.
850: *
851: * @return a string identifying this lock, as well as its lock state.
852: */
853: public String toString() {
854: Thread o = getOwner();
855: return super .toString()
856: + ((o == null) ? "[Unlocked]" : "[Locked by thread "
857: + o.getName() + "]");
858: }
859:
860: private CondVar asCondVar(Condition condition) {
861: if (condition == null)
862: throw new NullPointerException();
863: if (!(condition instanceof CondVar))
864: throw new IllegalArgumentException("not owner");
865: CondVar condVar = (CondVar) condition;
866: if (condVar.lock != this )
867: throw new IllegalArgumentException("not owner");
868: return condVar;
869: }
870: }
|