001 /*
002 * Copyright (C) 2010 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017 package com.google.common.util.concurrent;
018
019 import static com.google.common.base.Preconditions.checkNotNull;
020
021 import com.google.common.annotations.Beta;
022 import com.google.common.base.Throwables;
023 import com.google.common.collect.Lists;
024
025 import java.util.ArrayList;
026 import java.util.concurrent.TimeUnit;
027 import java.util.concurrent.locks.Condition;
028 import java.util.concurrent.locks.ReentrantLock;
029
030 import javax.annotation.Nullable;
031 import javax.annotation.concurrent.GuardedBy;
032
033 /**
034 * A synchronization abstraction supporting waiting on arbitrary boolean conditions.
035 *
036 * <p>This class is intended as a replacement for {@link ReentrantLock}. Code using {@code Monitor}
037 * is less error-prone and more readable than code using {@code ReentrantLock}, without significant
038 * performance loss. {@code Monitor} even has the potential for performance gain by optimizing the
039 * evaluation and signaling of conditions. Signaling is entirely
040 * <a href="http://en.wikipedia.org/wiki/Monitor_(synchronization)#Implicit_signaling">
041 * implicit</a>.
042 * By eliminating explicit signaling, this class can guarantee that only one thread is awakened
043 * when a condition becomes true (no "signaling storms" due to use of {@link
044 * java.util.concurrent.locks.Condition#signalAll Condition.signalAll}) and that no signals are lost
045 * (no "hangs" due to incorrect use of {@link java.util.concurrent.locks.Condition#signal
046 * Condition.signal}).
047 *
048 * <p>A thread is said to <i>occupy</i> a monitor if it has <i>entered</i> the monitor but not yet
049 * <i>left</i>. Only one thread may occupy a given monitor at any moment. A monitor is also
050 * reentrant, so a thread may enter a monitor any number of times, and then must leave the same
051 * number of times. The <i>enter</i> and <i>leave</i> operations have the same synchronization
052 * semantics as the built-in Java language synchronization primitives.
053 *
054 * <p>A call to any of the <i>enter</i> methods with <b>void</b> return type should always be
055 * followed immediately by a <i>try/finally</i> block to ensure that the current thread leaves the
056 * monitor cleanly: <pre> {@code
057 *
058 * monitor.enter();
059 * try {
060 * // do things while occupying the monitor
061 * } finally {
062 * monitor.leave();
063 * }}</pre>
064 *
065 * A call to any of the <i>enter</i> methods with <b>boolean</b> return type should always appear as
066 * the condition of an <i>if</i> statement containing a <i>try/finally</i> block to ensure that the
067 * current thread leaves the monitor cleanly: <pre> {@code
068 *
069 * if (monitor.tryEnter()) {
070 * try {
071 * // do things while occupying the monitor
072 * } finally {
073 * monitor.leave();
074 * }
075 * } else {
076 * // do other things since the monitor was not available
077 * }}</pre>
078 *
079 * <h2>Comparison with {@code synchronized} and {@code ReentrantLock}</h2>
080 *
081 * <p>The following examples show a simple threadsafe holder expressed using {@code synchronized},
082 * {@link ReentrantLock}, and {@code Monitor}.
083 *
084 * <h3>{@code synchronized}</h3>
085 *
086 * <p>This version is the fewest lines of code, largely because the synchronization mechanism used
087 * is built into the language and runtime. But the programmer has to remember to avoid a couple of
088 * common bugs: The {@code wait()} must be inside a {@code while} instead of an {@code if}, and
089 * {@code notifyAll()} must be used instead of {@code notify()} because there are two different
090 * logical conditions being awaited. <pre> {@code
091 *
092 * public class SafeBox<V> {
093 * private V value;
094 *
095 * public synchronized V get() throws InterruptedException {
096 * while (value == null) {
097 * wait();
098 * }
099 * V result = value;
100 * value = null;
101 * notifyAll();
102 * return result;
103 * }
104 *
105 * public synchronized void set(V newValue) throws InterruptedException {
106 * while (value != null) {
107 * wait();
108 * }
109 * value = newValue;
110 * notifyAll();
111 * }
112 * }}</pre>
113 *
114 * <h3>{@code ReentrantLock}</h3>
115 *
116 * <p>This version is much more verbose than the {@code synchronized} version, and still suffers
117 * from the need for the programmer to remember to use {@code while} instead of {@code if}.
118 * However, one advantage is that we can introduce two separate {@code Condition} objects, which
119 * allows us to use {@code signal()} instead of {@code signalAll()}, which may be a performance
120 * benefit. <pre> {@code
121 *
122 * public class SafeBox<V> {
123 * private final ReentrantLock lock = new ReentrantLock();
124 * private final Condition valuePresent = lock.newCondition();
125 * private final Condition valueAbsent = lock.newCondition();
126 * private V value;
127 *
128 * public V get() throws InterruptedException {
129 * lock.lock();
130 * try {
131 * while (value == null) {
132 * valuePresent.await();
133 * }
134 * V result = value;
135 * value = null;
136 * valueAbsent.signal();
137 * return result;
138 * } finally {
139 * lock.unlock();
140 * }
141 * }
142 *
143 * public void set(V newValue) throws InterruptedException {
144 * lock.lock();
145 * try {
146 * while (value != null) {
147 * valueAbsent.await();
148 * }
149 * value = newValue;
150 * valuePresent.signal();
151 * } finally {
152 * lock.unlock();
153 * }
154 * }
155 * }}</pre>
156 *
157 * <h3>{@code Monitor}</h3>
158 *
159 * <p>This version adds some verbosity around the {@code Guard} objects, but removes that same
160 * verbosity, and more, from the {@code get} and {@code set} methods. {@code Monitor} implements the
161 * same efficient signaling as we had to hand-code in the {@code ReentrantLock} version above.
162 * Finally, the programmer no longer has to hand-code the wait loop, and therefore doesn't have to
163 * remember to use {@code while} instead of {@code if}. <pre> {@code
164 *
165 * public class SafeBox<V> {
166 * private final Monitor monitor = new Monitor();
167 * private final Monitor.Guard valuePresent = new Monitor.Guard(monitor) {
168 * public boolean isSatisfied() {
169 * return value != null;
170 * }
171 * };
172 * private final Monitor.Guard valueAbsent = new Monitor.Guard(monitor) {
173 * public boolean isSatisfied() {
174 * return value == null;
175 * }
176 * };
177 * private V value;
178 *
179 * public V get() throws InterruptedException {
180 * monitor.enterWhen(valuePresent);
181 * try {
182 * V result = value;
183 * value = null;
184 * return result;
185 * } finally {
186 * monitor.leave();
187 * }
188 * }
189 *
190 * public void set(V newValue) throws InterruptedException {
191 * monitor.enterWhen(valueAbsent);
192 * try {
193 * value = newValue;
194 * } finally {
195 * monitor.leave();
196 * }
197 * }
198 * }}</pre>
199 *
200 * @author Justin T. Sampson
201 * @since 10.0
202 */
203 @Beta
204 public final class Monitor {
205 // TODO: Use raw LockSupport or AbstractQueuedSynchronizer instead of ReentrantLock.
206
207 /**
208 * A boolean condition for which a thread may wait. A {@code Guard} is associated with a single
209 * {@code Monitor}. The monitor may check the guard at arbitrary times from any thread occupying
210 * the monitor, so code should not be written to rely on how often a guard might or might not be
211 * checked.
212 *
213 * <p>If a {@code Guard} is passed into any method of a {@code Monitor} other than the one it is
214 * associated with, an {@link IllegalMonitorStateException} is thrown.
215 *
216 * @since 10.0
217 */
218 @Beta
219 public abstract static class Guard {
220
221 final Monitor monitor;
222 final Condition condition;
223
224 @GuardedBy("monitor.lock")
225 int waiterCount = 0;
226
227 protected Guard(Monitor monitor) {
228 this.monitor = checkNotNull(monitor, "monitor");
229 this.condition = monitor.lock.newCondition();
230 }
231
232 /**
233 * Evaluates this guard's boolean condition. This method is always called with the associated
234 * monitor already occupied. Implementations of this method must depend only on state protected
235 * by the associated monitor, and must not modify that state.
236 */
237 public abstract boolean isSatisfied();
238
239
240 @Override
241 public final boolean equals(Object other) {
242 // Overridden as final to ensure identity semantics in Monitor.activeGuards.
243 return this == other;
244 }
245
246
247 @Override
248 public final int hashCode() {
249 // Overridden as final to ensure identity semantics in Monitor.activeGuards.
250 return super.hashCode();
251 }
252
253 }
254
255 /**
256 * Whether this monitor is fair.
257 */
258 private final boolean fair;
259
260 /**
261 * The lock underlying this monitor.
262 */
263 private final ReentrantLock lock;
264
265 /**
266 * The guards associated with this monitor that currently have waiters ({@code waiterCount > 0}).
267 * This is an ArrayList rather than, say, a HashSet so that iteration and almost all adds don't
268 * incur any object allocation overhead.
269 */
270 @GuardedBy("lock")
271 private final ArrayList<Guard> activeGuards = Lists.newArrayListWithCapacity(1);
272
273 /**
274 * Creates a monitor with a non-fair (but fast) ordering policy. Equivalent to {@code
275 * Monitor(false)}.
276 */
277 public Monitor() {
278 this(false);
279 }
280
281 /**
282 * Creates a monitor with the given ordering policy.
283 *
284 * @param fair whether this monitor should use a fair ordering policy rather than a non-fair (but
285 * fast) one
286 */
287 public Monitor(boolean fair) {
288 this.fair = fair;
289 this.lock = new ReentrantLock(fair);
290 }
291
292 /**
293 * Enters this monitor. Blocks indefinitely.
294 */
295 public void enter() {
296 lock.lock();
297 }
298
299 /**
300 * Enters this monitor. Blocks indefinitely, but may be interrupted.
301 */
302 public void enterInterruptibly() throws InterruptedException {
303 lock.lockInterruptibly();
304 }
305
306 /**
307 * Enters this monitor. Blocks at most the given time.
308 *
309 * @return whether the monitor was entered
310 */
311 public boolean enter(long time, TimeUnit unit) {
312 final ReentrantLock lock = this.lock;
313 if (!fair && lock.tryLock()) {
314 return true;
315 }
316 long startNanos = System.nanoTime();
317 long timeoutNanos = unit.toNanos(time);
318 long remainingNanos = timeoutNanos;
319 boolean interruptIgnored = false;
320 try {
321 while (true) {
322 try {
323 return lock.tryLock(remainingNanos, TimeUnit.NANOSECONDS);
324 } catch (InterruptedException ignored) {
325 interruptIgnored = true;
326 remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
327 }
328 }
329 } finally {
330 if (interruptIgnored) {
331 Thread.currentThread().interrupt();
332 }
333 }
334 }
335
336 /**
337 * Enters this monitor. Blocks at most the given time, and may be interrupted.
338 *
339 * @return whether the monitor was entered
340 */
341 public boolean enterInterruptibly(long time, TimeUnit unit) throws InterruptedException {
342 return lock.tryLock(time, unit);
343 }
344
345 /**
346 * Enters this monitor if it is possible to do so immediately. Does not block.
347 *
348 * <p><b>Note:</b> This method disregards the fairness setting of this monitor.
349 *
350 * @return whether the monitor was entered
351 */
352 public boolean tryEnter() {
353 return lock.tryLock();
354 }
355
356 /**
357 * Enters this monitor when the guard is satisfied. Blocks indefinitely, but may be interrupted.
358 */
359 public void enterWhen(Guard guard) throws InterruptedException {
360 if (guard.monitor != this) {
361 throw new IllegalMonitorStateException();
362 }
363 final ReentrantLock lock = this.lock;
364 boolean reentrant = lock.isHeldByCurrentThread();
365 boolean success = false;
366 lock.lockInterruptibly();
367 try {
368 waitInterruptibly(guard, reentrant);
369 success = true;
370 } finally {
371 if (!success) {
372 lock.unlock();
373 }
374 }
375 }
376
377 /**
378 * Enters this monitor when the guard is satisfied. Blocks indefinitely.
379 */
380 public void enterWhenUninterruptibly(Guard guard) {
381 if (guard.monitor != this) {
382 throw new IllegalMonitorStateException();
383 }
384 final ReentrantLock lock = this.lock;
385 boolean reentrant = lock.isHeldByCurrentThread();
386 boolean success = false;
387 lock.lock();
388 try {
389 waitUninterruptibly(guard, reentrant);
390 success = true;
391 } finally {
392 if (!success) {
393 lock.unlock();
394 }
395 }
396 }
397
398 /**
399 * Enters this monitor when the guard is satisfied. Blocks at most the given time, including both
400 * the time to acquire the lock and the time to wait for the guard to be satisfied, and may be
401 * interrupted.
402 *
403 * @return whether the monitor was entered
404 */
405 public boolean enterWhen(Guard guard, long time, TimeUnit unit) throws InterruptedException {
406 if (guard.monitor != this) {
407 throw new IllegalMonitorStateException();
408 }
409 final ReentrantLock lock = this.lock;
410 boolean reentrant = lock.isHeldByCurrentThread();
411 long remainingNanos;
412 if (!fair && lock.tryLock()) {
413 remainingNanos = unit.toNanos(time);
414 } else {
415 long startNanos = System.nanoTime();
416 if (!lock.tryLock(time, unit)) {
417 return false;
418 }
419 remainingNanos = unit.toNanos(time) - (System.nanoTime() - startNanos);
420 }
421 boolean satisfied = false;
422 try {
423 satisfied = waitInterruptibly(guard, remainingNanos, reentrant);
424 } finally {
425 if (!satisfied) {
426 lock.unlock();
427 }
428 }
429 return satisfied;
430 }
431
432 /**
433 * Enters this monitor when the guard is satisfied. Blocks at most the given time, including
434 * both the time to acquire the lock and the time to wait for the guard to be satisfied.
435 *
436 * @return whether the monitor was entered
437 */
438 public boolean enterWhenUninterruptibly(Guard guard, long time, TimeUnit unit) {
439 if (guard.monitor != this) {
440 throw new IllegalMonitorStateException();
441 }
442 final ReentrantLock lock = this.lock;
443 boolean reentrant = lock.isHeldByCurrentThread();
444 boolean interruptIgnored = false;
445 try {
446 long remainingNanos;
447 if (!fair && lock.tryLock()) {
448 remainingNanos = unit.toNanos(time);
449 } else {
450 long startNanos = System.nanoTime();
451 long timeoutNanos = unit.toNanos(time);
452 remainingNanos = timeoutNanos;
453 while (true) {
454 try {
455 if (lock.tryLock(remainingNanos, TimeUnit.NANOSECONDS)) {
456 break;
457 } else {
458 return false;
459 }
460 } catch (InterruptedException ignored) {
461 interruptIgnored = true;
462 } finally {
463 remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
464 }
465 }
466 }
467 boolean satisfied = false;
468 try {
469 satisfied = waitUninterruptibly(guard, remainingNanos, reentrant);
470 } finally {
471 if (!satisfied) {
472 lock.unlock();
473 }
474 }
475 return satisfied;
476 } finally {
477 if (interruptIgnored) {
478 Thread.currentThread().interrupt();
479 }
480 }
481 }
482
483 /**
484 * Enters this monitor if the guard is satisfied. Blocks indefinitely acquiring the lock, but
485 * does not wait for the guard to be satisfied.
486 *
487 * @return whether the monitor was entered
488 */
489 public boolean enterIf(Guard guard) {
490 if (guard.monitor != this) {
491 throw new IllegalMonitorStateException();
492 }
493 final ReentrantLock lock = this.lock;
494 lock.lock();
495 boolean satisfied = false;
496 try {
497 satisfied = guard.isSatisfied();
498 } finally {
499 if (!satisfied) {
500 lock.unlock();
501 }
502 }
503 return satisfied;
504 }
505
506 /**
507 * Enters this monitor if the guard is satisfied. Blocks indefinitely acquiring the lock, but does
508 * not wait for the guard to be satisfied, and may be interrupted.
509 *
510 * @return whether the monitor was entered
511 */
512 public boolean enterIfInterruptibly(Guard guard) throws InterruptedException {
513 if (guard.monitor != this) {
514 throw new IllegalMonitorStateException();
515 }
516 final ReentrantLock lock = this.lock;
517 lock.lockInterruptibly();
518 boolean satisfied = false;
519 try {
520 satisfied = guard.isSatisfied();
521 } finally {
522 if (!satisfied) {
523 lock.unlock();
524 }
525 }
526 return satisfied;
527 }
528
529 /**
530 * Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the
531 * lock, but does not wait for the guard to be satisfied.
532 *
533 * @return whether the monitor was entered
534 */
535 public boolean enterIf(Guard guard, long time, TimeUnit unit) {
536 if (guard.monitor != this) {
537 throw new IllegalMonitorStateException();
538 }
539 final ReentrantLock lock = this.lock;
540 if (!enter(time, unit)) {
541 return false;
542 }
543 boolean satisfied = false;
544 try {
545 satisfied = guard.isSatisfied();
546 } finally {
547 if (!satisfied) {
548 lock.unlock();
549 }
550 }
551 return satisfied;
552 }
553
554 /**
555 * Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the
556 * lock, but does not wait for the guard to be satisfied, and may be interrupted.
557 *
558 * @return whether the monitor was entered
559 */
560 public boolean enterIfInterruptibly(Guard guard, long time, TimeUnit unit)
561 throws InterruptedException {
562 if (guard.monitor != this) {
563 throw new IllegalMonitorStateException();
564 }
565 final ReentrantLock lock = this.lock;
566 if (!lock.tryLock(time, unit)) {
567 return false;
568 }
569 boolean satisfied = false;
570 try {
571 satisfied = guard.isSatisfied();
572 } finally {
573 if (!satisfied) {
574 lock.unlock();
575 }
576 }
577 return satisfied;
578 }
579
580 /**
581 * Enters this monitor if it is possible to do so immediately and the guard is satisfied. Does not
582 * block acquiring the lock and does not wait for the guard to be satisfied.
583 *
584 * <p><b>Note:</b> This method disregards the fairness setting of this monitor.
585 *
586 * @return whether the monitor was entered
587 */
588 public boolean tryEnterIf(Guard guard) {
589 if (guard.monitor != this) {
590 throw new IllegalMonitorStateException();
591 }
592 final ReentrantLock lock = this.lock;
593 if (!lock.tryLock()) {
594 return false;
595 }
596 boolean satisfied = false;
597 try {
598 satisfied = guard.isSatisfied();
599 } finally {
600 if (!satisfied) {
601 lock.unlock();
602 }
603 }
604 return satisfied;
605 }
606
607 /**
608 * Waits for the guard to be satisfied. Waits indefinitely, but may be interrupted. May be
609 * called only by a thread currently occupying this monitor.
610 */
611 public void waitFor(Guard guard) throws InterruptedException {
612 if (guard.monitor != this) {
613 throw new IllegalMonitorStateException();
614 }
615 if (!lock.isHeldByCurrentThread()) {
616 throw new IllegalMonitorStateException();
617 }
618 waitInterruptibly(guard, true);
619 }
620
621 /**
622 * Waits for the guard to be satisfied. Waits indefinitely. May be called only by a thread
623 * currently occupying this monitor.
624 */
625 public void waitForUninterruptibly(Guard guard) {
626 if (guard.monitor != this) {
627 throw new IllegalMonitorStateException();
628 }
629 if (!lock.isHeldByCurrentThread()) {
630 throw new IllegalMonitorStateException();
631 }
632 waitUninterruptibly(guard, true);
633 }
634
635 /**
636 * Waits for the guard to be satisfied. Waits at most the given time, and may be interrupted.
637 * May be called only by a thread currently occupying this monitor.
638 *
639 * @return whether the guard is now satisfied
640 */
641 public boolean waitFor(Guard guard, long time, TimeUnit unit) throws InterruptedException {
642 if (guard.monitor != this) {
643 throw new IllegalMonitorStateException();
644 }
645 if (!lock.isHeldByCurrentThread()) {
646 throw new IllegalMonitorStateException();
647 }
648 return waitInterruptibly(guard, unit.toNanos(time), true);
649 }
650
651 /**
652 * Waits for the guard to be satisfied. Waits at most the given time. May be called only by a
653 * thread currently occupying this monitor.
654 *
655 * @return whether the guard is now satisfied
656 */
657 public boolean waitForUninterruptibly(Guard guard, long time, TimeUnit unit) {
658 if (guard.monitor != this) {
659 throw new IllegalMonitorStateException();
660 }
661 if (!lock.isHeldByCurrentThread()) {
662 throw new IllegalMonitorStateException();
663 }
664 return waitUninterruptibly(guard, unit.toNanos(time), true);
665 }
666
667 /**
668 * Leaves this monitor. May be called only by a thread currently occupying this monitor.
669 */
670 public void leave() {
671 final ReentrantLock lock = this.lock;
672 if (!lock.isHeldByCurrentThread()) {
673 throw new IllegalMonitorStateException();
674 }
675 try {
676 signalConditionsOfSatisfiedGuards(null);
677 } finally {
678 lock.unlock();
679 }
680 }
681
682 /**
683 * Returns whether this monitor is using a fair ordering policy.
684 */
685 public boolean isFair() {
686 return lock.isFair();
687 }
688
689 /**
690 * Returns whether this monitor is occupied by any thread. This method is designed for use in
691 * monitoring of the system state, not for synchronization control.
692 */
693 public boolean isOccupied() {
694 return lock.isLocked();
695 }
696
697 /**
698 * Returns whether the current thread is occupying this monitor (has entered more times than it
699 * has left).
700 */
701 public boolean isOccupiedByCurrentThread() {
702 return lock.isHeldByCurrentThread();
703 }
704
705 /**
706 * Returns the number of times the current thread has entered this monitor in excess of the number
707 * of times it has left. Returns 0 if the current thread is not occupying this monitor.
708 */
709 public int getOccupiedDepth() {
710 return lock.getHoldCount();
711 }
712
713 /**
714 * Returns an estimate of the number of threads waiting to enter this monitor. The value is only
715 * an estimate because the number of threads may change dynamically while this method traverses
716 * internal data structures. This method is designed for use in monitoring of the system state,
717 * not for synchronization control.
718 */
719 public int getQueueLength() {
720 return lock.getQueueLength();
721 }
722
723 /**
724 * Returns whether any threads are waiting to enter this monitor. Note that because cancellations
725 * may occur at any time, a {@code true} return does not guarantee that any other thread will ever
726 * enter this monitor. This method is designed primarily for use in monitoring of the system
727 * state.
728 */
729 public boolean hasQueuedThreads() {
730 return lock.hasQueuedThreads();
731 }
732
733 /**
734 * Queries whether the given thread is waiting to enter this monitor. Note that because
735 * cancellations may occur at any time, a {@code true} return does not guarantee that this thread
736 * will ever enter this monitor. This method is designed primarily for use in monitoring of the
737 * system state.
738 */
739 public boolean hasQueuedThread(Thread thread) {
740 return lock.hasQueuedThread(thread);
741 }
742
743 /**
744 * Queries whether any threads are waiting for the given guard to become satisfied. Note that
745 * because timeouts and interrupts may occur at any time, a {@code true} return does not guarantee
746 * that the guard becoming satisfied in the future will awaken any threads. This method is
747 * designed primarily for use in monitoring of the system state.
748 */
749 public boolean hasWaiters(Guard guard) {
750 if (guard.monitor != this) {
751 throw new IllegalMonitorStateException();
752 }
753 lock.lock();
754 try {
755 return guard.waiterCount > 0;
756 } finally {
757 lock.unlock();
758 }
759 }
760
761 /**
762 * Returns an estimate of the number of threads waiting for the given guard to become satisfied.
763 * Note that because timeouts and interrupts may occur at any time, the estimate serves only as an
764 * upper bound on the actual number of waiters. This method is designed for use in monitoring of
765 * the system state, not for synchronization control.
766 */
767 public int getWaitQueueLength(Guard guard) {
768 if (guard.monitor != this) {
769 throw new IllegalMonitorStateException();
770 }
771 lock.lock();
772 try {
773 return guard.waiterCount;
774 } finally {
775 lock.unlock();
776 }
777 }
778
779 @GuardedBy("lock")
780 private void signalConditionsOfSatisfiedGuards(@Nullable Guard interruptedGuard) {
781 final ArrayList<Guard> guards = this.activeGuards;
782 final int guardCount = guards.size();
783 try {
784 for (int i = 0; i < guardCount; i++) {
785 Guard guard = guards.get(i);
786 if ((guard == interruptedGuard) && (guard.waiterCount == 1)) {
787 // That one waiter was just interrupted and is throwing InterruptedException rather than
788 // paying attention to the guard being satisfied, so find another waiter on another guard.
789 continue;
790 }
791 if (guard.isSatisfied()) {
792 guard.condition.signal();
793 return;
794 }
795 }
796 } catch (Throwable throwable) {
797 for (int i = 0; i < guardCount; i++) {
798 Guard guard = guards.get(i);
799 guard.condition.signalAll();
800 }
801 throw Throwables.propagate(throwable);
802 }
803 }
804
805 @GuardedBy("lock")
806 private void incrementWaiters(Guard guard) {
807 int waiters = guard.waiterCount++;
808 if (waiters == 0) {
809 activeGuards.add(guard);
810 }
811 }
812
813 @GuardedBy("lock")
814 private void decrementWaiters(Guard guard) {
815 int waiters = --guard.waiterCount;
816 if (waiters == 0) {
817 activeGuards.remove(guard);
818 }
819 }
820
821 @GuardedBy("lock")
822 private void waitInterruptibly(Guard guard, boolean signalBeforeWaiting)
823 throws InterruptedException {
824 if (!guard.isSatisfied()) {
825 if (signalBeforeWaiting) {
826 signalConditionsOfSatisfiedGuards(null);
827 }
828 incrementWaiters(guard);
829 try {
830 final Condition condition = guard.condition;
831 do {
832 try {
833 condition.await();
834 } catch (InterruptedException interrupt) {
835 try {
836 signalConditionsOfSatisfiedGuards(guard);
837 } catch (Throwable throwable) {
838 Thread.currentThread().interrupt();
839 throw Throwables.propagate(throwable);
840 }
841 throw interrupt;
842 }
843 } while (!guard.isSatisfied());
844 } finally {
845 decrementWaiters(guard);
846 }
847 }
848 }
849
850 @GuardedBy("lock")
851 private void waitUninterruptibly(Guard guard, boolean signalBeforeWaiting) {
852 if (!guard.isSatisfied()) {
853 if (signalBeforeWaiting) {
854 signalConditionsOfSatisfiedGuards(null);
855 }
856 incrementWaiters(guard);
857 try {
858 final Condition condition = guard.condition;
859 do {
860 condition.awaitUninterruptibly();
861 } while (!guard.isSatisfied());
862 } finally {
863 decrementWaiters(guard);
864 }
865 }
866 }
867
868 @GuardedBy("lock")
869 private boolean waitInterruptibly(Guard guard, long remainingNanos, boolean signalBeforeWaiting)
870 throws InterruptedException {
871 if (!guard.isSatisfied()) {
872 if (signalBeforeWaiting) {
873 signalConditionsOfSatisfiedGuards(null);
874 }
875 incrementWaiters(guard);
876 try {
877 final Condition condition = guard.condition;
878 do {
879 if (remainingNanos <= 0) {
880 return false;
881 }
882 try {
883 remainingNanos = condition.awaitNanos(remainingNanos);
884 } catch (InterruptedException interrupt) {
885 try {
886 signalConditionsOfSatisfiedGuards(guard);
887 } catch (Throwable throwable) {
888 Thread.currentThread().interrupt();
889 throw Throwables.propagate(throwable);
890 }
891 throw interrupt;
892 }
893 } while (!guard.isSatisfied());
894 } finally {
895 decrementWaiters(guard);
896 }
897 }
898 return true;
899 }
900
901 @GuardedBy("lock")
902 private boolean waitUninterruptibly(Guard guard, long timeoutNanos,
903 boolean signalBeforeWaiting) {
904 if (!guard.isSatisfied()) {
905 long startNanos = System.nanoTime();
906 if (signalBeforeWaiting) {
907 signalConditionsOfSatisfiedGuards(null);
908 }
909 boolean interruptIgnored = false;
910 try {
911 incrementWaiters(guard);
912 try {
913 final Condition condition = guard.condition;
914 long remainingNanos = timeoutNanos;
915 do {
916 if (remainingNanos <= 0) {
917 return false;
918 }
919 try {
920 remainingNanos = condition.awaitNanos(remainingNanos);
921 } catch (InterruptedException ignored) {
922 try {
923 signalConditionsOfSatisfiedGuards(guard);
924 } catch (Throwable throwable) {
925 Thread.currentThread().interrupt();
926 throw Throwables.propagate(throwable);
927 }
928 interruptIgnored = true;
929 remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
930 }
931 } while (!guard.isSatisfied());
932 } finally {
933 decrementWaiters(guard);
934 }
935 } finally {
936 if (interruptIgnored) {
937 Thread.currentThread().interrupt();
938 }
939 }
940 }
941 return true;
942 }
943
944 }