javadoc.src-html.com.google.common.util.concurrent.Monitor.Guard.html Maven / Gradle / Ivy
The newest version!
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 @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 }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy