1/*
2 * Copyright (C) 2010 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.util.concurrent;
18
19import static com.google.common.base.Preconditions.checkNotNull;
20
21import com.google.common.annotations.Beta;
22import com.google.common.base.Throwables;
23import com.google.common.collect.Lists;
24
25import java.util.ArrayList;
26import java.util.concurrent.TimeUnit;
27import java.util.concurrent.locks.Condition;
28import java.util.concurrent.locks.ReentrantLock;
29
30import javax.annotation.Nullable;
31import javax.annotation.concurrent.GuardedBy;
32
33/**
34 * A synchronization abstraction supporting waiting on arbitrary boolean conditions.
35 *
36 * <p>This class is intended as a replacement for {@link ReentrantLock}. Code using {@code Monitor}
37 * is less error-prone and more readable than code using {@code ReentrantLock}, without significant
38 * performance loss. {@code Monitor} even has the potential for performance gain by optimizing the
39 * evaluation and signaling of conditions.  Signaling is entirely
40 * <a href="http://en.wikipedia.org/wiki/Monitor_(synchronization)#Implicit_signaling">
41 * implicit</a>.
42 * By eliminating explicit signaling, this class can guarantee that only one thread is awakened
43 * when a condition becomes true (no "signaling storms" due to use of {@link
44 * java.util.concurrent.locks.Condition#signalAll Condition.signalAll}) and that no signals are lost
45 * (no "hangs" due to incorrect use of {@link java.util.concurrent.locks.Condition#signal
46 * Condition.signal}).
47 *
48 * <p>A thread is said to <i>occupy</i> a monitor if it has <i>entered</i> the monitor but not yet
49 * <i>left</i>. Only one thread may occupy a given monitor at any moment. A monitor is also
50 * reentrant, so a thread may enter a monitor any number of times, and then must leave the same
51 * number of times. The <i>enter</i> and <i>leave</i> operations have the same synchronization
52 * semantics as the built-in Java language synchronization primitives.
53 *
54 * <p>A call to any of the <i>enter</i> methods with <b>void</b> return type should always be
55 * followed immediately by a <i>try/finally</i> block to ensure that the current thread leaves the
56 * monitor cleanly: <pre>   {@code
57 *
58 *   monitor.enter();
59 *   try {
60 *     // do things while occupying the monitor
61 *   } finally {
62 *     monitor.leave();
63 *   }}</pre>
64 *
65 * A call to any of the <i>enter</i> methods with <b>boolean</b> return type should always appear as
66 * the condition of an <i>if</i> statement containing a <i>try/finally</i> block to ensure that the
67 * current thread leaves the monitor cleanly: <pre>   {@code
68 *
69 *   if (monitor.tryEnter()) {
70 *     try {
71 *       // do things while occupying the monitor
72 *     } finally {
73 *       monitor.leave();
74 *     }
75 *   } else {
76 *     // do other things since the monitor was not available
77 *   }}</pre>
78 *
79 * <h2>Comparison with {@code synchronized} and {@code ReentrantLock}</h2>
80 *
81 * <p>The following examples show a simple threadsafe holder expressed using {@code synchronized},
82 * {@link ReentrantLock}, and {@code Monitor}.
83 *
84 * <h3>{@code synchronized}</h3>
85 *
86 * <p>This version is the fewest lines of code, largely because the synchronization mechanism used
87 * is built into the language and runtime. But the programmer has to remember to avoid a couple of
88 * common bugs: The {@code wait()} must be inside a {@code while} instead of an {@code if}, and
89 * {@code notifyAll()} must be used instead of {@code notify()} because there are two different
90 * logical conditions being awaited. <pre>   {@code
91 *
92 *   public class SafeBox<V> {
93 *     private V value;
94 *
95 *     public synchronized V get() throws InterruptedException {
96 *       while (value == null) {
97 *         wait();
98 *       }
99 *       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
204public 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    @Override
240    public final boolean equals(Object other) {
241      // Overridden as final to ensure identity semantics in Monitor.activeGuards.
242      return this == other;
243    }
244
245    @Override
246    public final int hashCode() {
247      // Overridden as final to ensure identity semantics in Monitor.activeGuards.
248      return super.hashCode();
249    }
250
251  }
252
253  /**
254   * Whether this monitor is fair.
255   */
256  private final boolean fair;
257
258  /**
259   * The lock underlying this monitor.
260   */
261  private final ReentrantLock lock;
262
263  /**
264   * The guards associated with this monitor that currently have waiters ({@code waiterCount > 0}).
265   * This is an ArrayList rather than, say, a HashSet so that iteration and almost all adds don't
266   * incur any object allocation overhead.
267   */
268  @GuardedBy("lock")
269  private final ArrayList<Guard> activeGuards = Lists.newArrayListWithCapacity(1);
270
271  /**
272   * Creates a monitor with a non-fair (but fast) ordering policy. Equivalent to {@code
273   * Monitor(false)}.
274   */
275  public Monitor() {
276    this(false);
277  }
278
279  /**
280   * Creates a monitor with the given ordering policy.
281   *
282   * @param fair whether this monitor should use a fair ordering policy rather than a non-fair (but
283   *        fast) one
284   */
285  public Monitor(boolean fair) {
286    this.fair = fair;
287    this.lock = new ReentrantLock(fair);
288  }
289
290  /**
291   * Enters this monitor. Blocks indefinitely.
292   */
293  public void enter() {
294    lock.lock();
295  }
296
297  /**
298   * Enters this monitor. Blocks indefinitely, but may be interrupted.
299   */
300  public void enterInterruptibly() throws InterruptedException {
301    lock.lockInterruptibly();
302  }
303
304  /**
305   * Enters this monitor. Blocks at most the given time.
306   *
307   * @return whether the monitor was entered
308   */
309  public boolean enter(long time, TimeUnit unit) {
310    final ReentrantLock lock = this.lock;
311    if (!fair && lock.tryLock()) {
312      return true;
313    }
314    long startNanos = System.nanoTime();
315    long timeoutNanos = unit.toNanos(time);
316    long remainingNanos = timeoutNanos;
317    boolean interruptIgnored = false;
318    try {
319      while (true) {
320        try {
321          return lock.tryLock(remainingNanos, TimeUnit.NANOSECONDS);
322        } catch (InterruptedException ignored) {
323          interruptIgnored = true;
324          remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
325        }
326      }
327    } finally {
328      if (interruptIgnored) {
329        Thread.currentThread().interrupt();
330      }
331    }
332  }
333
334  /**
335   * Enters this monitor. Blocks at most the given time, and may be interrupted.
336   *
337   * @return whether the monitor was entered
338   */
339  public boolean enterInterruptibly(long time, TimeUnit unit) throws InterruptedException {
340    return lock.tryLock(time, unit);
341  }
342
343  /**
344   * Enters this monitor if it is possible to do so immediately. Does not block.
345   *
346   * <p><b>Note:</b> This method disregards the fairness setting of this monitor.
347   *
348   * @return whether the monitor was entered
349   */
350  public boolean tryEnter() {
351    return lock.tryLock();
352  }
353
354  /**
355   * Enters this monitor when the guard is satisfied. Blocks indefinitely, but may be interrupted.
356   */
357  public void enterWhen(Guard guard) throws InterruptedException {
358    if (guard.monitor != this) {
359      throw new IllegalMonitorStateException();
360    }
361    final ReentrantLock lock = this.lock;
362    boolean reentrant = lock.isHeldByCurrentThread();
363    boolean success = false;
364    lock.lockInterruptibly();
365    try {
366      waitInterruptibly(guard, reentrant);
367      success = true;
368    } finally {
369      if (!success) {
370        lock.unlock();
371      }
372    }
373  }
374
375  /**
376   * Enters this monitor when the guard is satisfied. Blocks indefinitely.
377   */
378  public void enterWhenUninterruptibly(Guard guard) {
379    if (guard.monitor != this) {
380      throw new IllegalMonitorStateException();
381    }
382    final ReentrantLock lock = this.lock;
383    boolean reentrant = lock.isHeldByCurrentThread();
384    boolean success = false;
385    lock.lock();
386    try {
387      waitUninterruptibly(guard, reentrant);
388      success = true;
389    } finally {
390      if (!success) {
391        lock.unlock();
392      }
393    }
394  }
395
396  /**
397   * Enters this monitor when the guard is satisfied. Blocks at most the given time, including both
398   * the time to acquire the lock and the time to wait for the guard to be satisfied, and may be
399   * interrupted.
400   *
401   * @return whether the monitor was entered
402   */
403  public boolean enterWhen(Guard guard, long time, TimeUnit unit) throws InterruptedException {
404    if (guard.monitor != this) {
405      throw new IllegalMonitorStateException();
406    }
407    final ReentrantLock lock = this.lock;
408    boolean reentrant = lock.isHeldByCurrentThread();
409    long remainingNanos;
410    if (!fair && lock.tryLock()) {
411      remainingNanos = unit.toNanos(time);
412    } else {
413      long startNanos = System.nanoTime();
414      if (!lock.tryLock(time, unit)) {
415        return false;
416      }
417      remainingNanos = unit.toNanos(time) - (System.nanoTime() - startNanos);
418    }
419    boolean satisfied = false;
420    try {
421      satisfied = waitInterruptibly(guard, remainingNanos, reentrant);
422    } finally {
423      if (!satisfied) {
424        lock.unlock();
425      }
426    }
427    return satisfied;
428  }
429
430  /**
431   * Enters this monitor when the guard is satisfied. Blocks at most the given time, including
432   * both the time to acquire the lock and the time to wait for the guard to be satisfied.
433   *
434   * @return whether the monitor was entered
435   */
436  public boolean enterWhenUninterruptibly(Guard guard, long time, TimeUnit unit) {
437    if (guard.monitor != this) {
438      throw new IllegalMonitorStateException();
439    }
440    final ReentrantLock lock = this.lock;
441    boolean reentrant = lock.isHeldByCurrentThread();
442    boolean interruptIgnored = false;
443    try {
444      long remainingNanos;
445      if (!fair && lock.tryLock()) {
446        remainingNanos = unit.toNanos(time);
447      } else {
448        long startNanos = System.nanoTime();
449        long timeoutNanos = unit.toNanos(time);
450        remainingNanos = timeoutNanos;
451        while (true) {
452          try {
453            if (lock.tryLock(remainingNanos, TimeUnit.NANOSECONDS)) {
454              break;
455            } else {
456              return false;
457            }
458          } catch (InterruptedException ignored) {
459            interruptIgnored = true;
460          } finally {
461            remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
462          }
463        }
464      }
465      boolean satisfied = false;
466      try {
467        satisfied = waitUninterruptibly(guard, remainingNanos, reentrant);
468      } finally {
469        if (!satisfied) {
470          lock.unlock();
471        }
472      }
473      return satisfied;
474    } finally {
475      if (interruptIgnored) {
476        Thread.currentThread().interrupt();
477      }
478    }
479  }
480
481  /**
482   * Enters this monitor if the guard is satisfied. Blocks indefinitely acquiring the lock, but
483   * does not wait for the guard to be satisfied.
484   *
485   * @return whether the monitor was entered
486   */
487  public boolean enterIf(Guard guard) {
488    if (guard.monitor != this) {
489      throw new IllegalMonitorStateException();
490    }
491    final ReentrantLock lock = this.lock;
492    lock.lock();
493    boolean satisfied = false;
494    try {
495      satisfied = guard.isSatisfied();
496    } finally {
497      if (!satisfied) {
498        lock.unlock();
499      }
500    }
501    return satisfied;
502  }
503
504  /**
505   * Enters this monitor if the guard is satisfied. Blocks indefinitely acquiring the lock, but does
506   * not wait for the guard to be satisfied, and may be interrupted.
507   *
508   * @return whether the monitor was entered
509   */
510  public boolean enterIfInterruptibly(Guard guard) throws InterruptedException {
511    if (guard.monitor != this) {
512      throw new IllegalMonitorStateException();
513    }
514    final ReentrantLock lock = this.lock;
515    lock.lockInterruptibly();
516    boolean satisfied = false;
517    try {
518      satisfied = guard.isSatisfied();
519    } finally {
520      if (!satisfied) {
521        lock.unlock();
522      }
523    }
524    return satisfied;
525  }
526
527  /**
528   * Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the
529   * lock, but does not wait for the guard to be satisfied.
530   *
531   * @return whether the monitor was entered
532   */
533  public boolean enterIf(Guard guard, long time, TimeUnit unit) {
534    if (guard.monitor != this) {
535      throw new IllegalMonitorStateException();
536    }
537    final ReentrantLock lock = this.lock;
538    if (!enter(time, unit)) {
539      return false;
540    }
541    boolean satisfied = false;
542    try {
543      satisfied = guard.isSatisfied();
544    } finally {
545      if (!satisfied) {
546        lock.unlock();
547      }
548    }
549    return satisfied;
550  }
551
552  /**
553   * Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the
554   * lock, but does not wait for the guard to be satisfied, and may be interrupted.
555   *
556   * @return whether the monitor was entered
557   */
558  public boolean enterIfInterruptibly(Guard guard, long time, TimeUnit unit)
559      throws InterruptedException {
560    if (guard.monitor != this) {
561      throw new IllegalMonitorStateException();
562    }
563    final ReentrantLock lock = this.lock;
564    if (!lock.tryLock(time, unit)) {
565      return false;
566    }
567    boolean satisfied = false;
568    try {
569      satisfied = guard.isSatisfied();
570    } finally {
571      if (!satisfied) {
572        lock.unlock();
573      }
574    }
575    return satisfied;
576  }
577
578  /**
579   * Enters this monitor if it is possible to do so immediately and the guard is satisfied. Does not
580   * block acquiring the lock and does not wait for the guard to be satisfied.
581   *
582   * <p><b>Note:</b> This method disregards the fairness setting of this monitor.
583   *
584   * @return whether the monitor was entered
585   */
586  public boolean tryEnterIf(Guard guard) {
587    if (guard.monitor != this) {
588      throw new IllegalMonitorStateException();
589    }
590    final ReentrantLock lock = this.lock;
591    if (!lock.tryLock()) {
592      return false;
593    }
594    boolean satisfied = false;
595    try {
596      satisfied = guard.isSatisfied();
597    } finally {
598      if (!satisfied) {
599        lock.unlock();
600      }
601    }
602    return satisfied;
603  }
604
605  /**
606   * Waits for the guard to be satisfied. Waits indefinitely, but may be interrupted. May be
607   * called only by a thread currently occupying this monitor.
608   */
609  public void waitFor(Guard guard) throws InterruptedException {
610    if (guard.monitor != this) {
611      throw new IllegalMonitorStateException();
612    }
613    if (!lock.isHeldByCurrentThread()) {
614      throw new IllegalMonitorStateException();
615    }
616    waitInterruptibly(guard, true);
617  }
618
619  /**
620   * Waits for the guard to be satisfied. Waits indefinitely. May be called only by a thread
621   * currently occupying this monitor.
622   */
623  public void waitForUninterruptibly(Guard guard) {
624    if (guard.monitor != this) {
625      throw new IllegalMonitorStateException();
626    }
627    if (!lock.isHeldByCurrentThread()) {
628      throw new IllegalMonitorStateException();
629    }
630    waitUninterruptibly(guard, true);
631  }
632
633  /**
634   * Waits for the guard to be satisfied. Waits at most the given time, and may be interrupted.
635   * May be called only by a thread currently occupying this monitor.
636   *
637   * @return whether the guard is now satisfied
638   */
639  public boolean waitFor(Guard guard, long time, TimeUnit unit) throws InterruptedException {
640    if (guard.monitor != this) {
641      throw new IllegalMonitorStateException();
642    }
643    if (!lock.isHeldByCurrentThread()) {
644      throw new IllegalMonitorStateException();
645    }
646    return waitInterruptibly(guard, unit.toNanos(time), true);
647  }
648
649  /**
650   * Waits for the guard to be satisfied. Waits at most the given time. May be called only by a
651   * thread currently occupying this monitor.
652   *
653   * @return whether the guard is now satisfied
654   */
655  public boolean waitForUninterruptibly(Guard guard, long time, TimeUnit unit) {
656    if (guard.monitor != this) {
657      throw new IllegalMonitorStateException();
658    }
659    if (!lock.isHeldByCurrentThread()) {
660      throw new IllegalMonitorStateException();
661    }
662    return waitUninterruptibly(guard, unit.toNanos(time), true);
663  }
664
665  /**
666   * Leaves this monitor. May be called only by a thread currently occupying this monitor.
667   */
668  public void leave() {
669    final ReentrantLock lock = this.lock;
670    if (!lock.isHeldByCurrentThread()) {
671      throw new IllegalMonitorStateException();
672    }
673    try {
674      signalConditionsOfSatisfiedGuards(null);
675    } finally {
676      lock.unlock();
677    }
678  }
679
680  /**
681   * Returns whether this monitor is using a fair ordering policy.
682   */
683  public boolean isFair() {
684    return lock.isFair();
685  }
686
687  /**
688   * Returns whether this monitor is occupied by any thread. This method is designed for use in
689   * monitoring of the system state, not for synchronization control.
690   */
691  public boolean isOccupied() {
692    return lock.isLocked();
693  }
694
695  /**
696   * Returns whether the current thread is occupying this monitor (has entered more times than it
697   * has left).
698   */
699  public boolean isOccupiedByCurrentThread() {
700    return lock.isHeldByCurrentThread();
701  }
702
703  /**
704   * Returns the number of times the current thread has entered this monitor in excess of the number
705   * of times it has left. Returns 0 if the current thread is not occupying this monitor.
706   */
707  public int getOccupiedDepth() {
708    return lock.getHoldCount();
709  }
710
711  /**
712   * Returns an estimate of the number of threads waiting to enter this monitor. The value is only
713   * an estimate because the number of threads may change dynamically while this method traverses
714   * internal data structures. This method is designed for use in monitoring of the system state,
715   * not for synchronization control.
716   */
717  public int getQueueLength() {
718    return lock.getQueueLength();
719  }
720
721  /**
722   * Returns whether any threads are waiting to enter this monitor. Note that because cancellations
723   * may occur at any time, a {@code true} return does not guarantee that any other thread will ever
724   * enter this monitor. This method is designed primarily for use in monitoring of the system
725   * state.
726   */
727  public boolean hasQueuedThreads() {
728    return lock.hasQueuedThreads();
729  }
730
731  /**
732   * Queries whether the given thread is waiting to enter this monitor. Note that because
733   * cancellations may occur at any time, a {@code true} return does not guarantee that this thread
734   * will ever enter this monitor. This method is designed primarily for use in monitoring of the
735   * system state.
736   */
737  public boolean hasQueuedThread(Thread thread) {
738    return lock.hasQueuedThread(thread);
739  }
740
741  /**
742   * Queries whether any threads are waiting for the given guard to become satisfied. Note that
743   * because timeouts and interrupts may occur at any time, a {@code true} return does not guarantee
744   * that the guard becoming satisfied in the future will awaken any threads. This method is
745   * designed primarily for use in monitoring of the system state.
746   */
747  public boolean hasWaiters(Guard guard) {
748    if (guard.monitor != this) {
749      throw new IllegalMonitorStateException();
750    }
751    lock.lock();
752    try {
753      return guard.waiterCount > 0;
754    } finally {
755      lock.unlock();
756    }
757  }
758
759  /**
760   * Returns an estimate of the number of threads waiting for the given guard to become satisfied.
761   * Note that because timeouts and interrupts may occur at any time, the estimate serves only as an
762   * upper bound on the actual number of waiters. This method is designed for use in monitoring of
763   * the system state, not for synchronization control.
764   */
765  public int getWaitQueueLength(Guard guard) {
766    if (guard.monitor != this) {
767      throw new IllegalMonitorStateException();
768    }
769    lock.lock();
770    try {
771      return guard.waiterCount;
772    } finally {
773      lock.unlock();
774    }
775  }
776
777  @GuardedBy("lock")
778  private void signalConditionsOfSatisfiedGuards(@Nullable Guard interruptedGuard) {
779    final ArrayList<Guard> guards = this.activeGuards;
780    final int guardCount = guards.size();
781    try {
782      for (int i = 0; i < guardCount; i++) {
783        Guard guard = guards.get(i);
784        if ((guard == interruptedGuard) && (guard.waiterCount == 1)) {
785          // That one waiter was just interrupted and is throwing InterruptedException rather than
786          // paying attention to the guard being satisfied, so find another waiter on another guard.
787          continue;
788        }
789        if (guard.isSatisfied()) {
790          guard.condition.signal();
791          return;
792        }
793      }
794    } catch (Throwable throwable) {
795      for (int i = 0; i < guardCount; i++) {
796        Guard guard = guards.get(i);
797        guard.condition.signalAll();
798      }
799      throw Throwables.propagate(throwable);
800    }
801  }
802
803  @GuardedBy("lock")
804  private void incrementWaiters(Guard guard) {
805    int waiters = guard.waiterCount++;
806    if (waiters == 0) {
807      activeGuards.add(guard);
808    }
809  }
810
811  @GuardedBy("lock")
812  private void decrementWaiters(Guard guard) {
813    int waiters = --guard.waiterCount;
814    if (waiters == 0) {
815      activeGuards.remove(guard);
816    }
817  }
818
819  @GuardedBy("lock")
820  private void waitInterruptibly(Guard guard, boolean signalBeforeWaiting)
821      throws InterruptedException {
822    if (!guard.isSatisfied()) {
823      if (signalBeforeWaiting) {
824        signalConditionsOfSatisfiedGuards(null);
825      }
826      incrementWaiters(guard);
827      try {
828        final Condition condition = guard.condition;
829        do {
830          try {
831            condition.await();
832          } catch (InterruptedException interrupt) {
833            try {
834              signalConditionsOfSatisfiedGuards(guard);
835            } catch (Throwable throwable) {
836              Thread.currentThread().interrupt();
837              throw Throwables.propagate(throwable);
838            }
839            throw interrupt;
840          }
841        } while (!guard.isSatisfied());
842      } finally {
843        decrementWaiters(guard);
844      }
845    }
846  }
847
848  @GuardedBy("lock")
849  private void waitUninterruptibly(Guard guard, boolean signalBeforeWaiting) {
850    if (!guard.isSatisfied()) {
851      if (signalBeforeWaiting) {
852        signalConditionsOfSatisfiedGuards(null);
853      }
854      incrementWaiters(guard);
855      try {
856        final Condition condition = guard.condition;
857        do {
858          condition.awaitUninterruptibly();
859        } while (!guard.isSatisfied());
860      } finally {
861        decrementWaiters(guard);
862      }
863    }
864  }
865
866  @GuardedBy("lock")
867  private boolean waitInterruptibly(Guard guard, long remainingNanos, boolean signalBeforeWaiting)
868      throws InterruptedException {
869    if (!guard.isSatisfied()) {
870      if (signalBeforeWaiting) {
871        signalConditionsOfSatisfiedGuards(null);
872      }
873      incrementWaiters(guard);
874      try {
875        final Condition condition = guard.condition;
876        do {
877          if (remainingNanos <= 0) {
878            return false;
879          }
880          try {
881            remainingNanos = condition.awaitNanos(remainingNanos);
882          } catch (InterruptedException interrupt) {
883            try {
884              signalConditionsOfSatisfiedGuards(guard);
885            } catch (Throwable throwable) {
886              Thread.currentThread().interrupt();
887              throw Throwables.propagate(throwable);
888            }
889            throw interrupt;
890          }
891        } while (!guard.isSatisfied());
892      } finally {
893        decrementWaiters(guard);
894      }
895    }
896    return true;
897  }
898
899  @GuardedBy("lock")
900  private boolean waitUninterruptibly(Guard guard, long timeoutNanos,
901      boolean signalBeforeWaiting) {
902    if (!guard.isSatisfied()) {
903      long startNanos = System.nanoTime();
904      if (signalBeforeWaiting) {
905        signalConditionsOfSatisfiedGuards(null);
906      }
907      boolean interruptIgnored = false;
908      try {
909        incrementWaiters(guard);
910        try {
911          final Condition condition = guard.condition;
912          long remainingNanos = timeoutNanos;
913          do {
914            if (remainingNanos <= 0) {
915              return false;
916            }
917            try {
918              remainingNanos = condition.awaitNanos(remainingNanos);
919            } catch (InterruptedException ignored) {
920              try {
921                signalConditionsOfSatisfiedGuards(guard);
922              } catch (Throwable throwable) {
923                Thread.currentThread().interrupt();
924                throw Throwables.propagate(throwable);
925              }
926              interruptIgnored = true;
927              remainingNanos = (timeoutNanos - (System.nanoTime() - startNanos));
928            }
929          } while (!guard.isSatisfied());
930        } finally {
931          decrementWaiters(guard);
932        }
933      } finally {
934        if (interruptIgnored) {
935          Thread.currentThread().interrupt();
936        }
937      }
938    }
939    return true;
940  }
941
942}
943