This class is intended as a replacement for ReentrantLock. Code using Monitor
is less error-prone and more readable than code using ReentrantLock, without significant
performance loss. Monitor even has the potential for performance gain by optimizing the
evaluation and signaling of conditions. Signaling is entirely implicit. By
eliminating explicit signaling, this class can guarantee that only one thread is awakened when a
condition becomes true (no "signaling storms" due to use of Condition.) and that no signals are lost
(no "hangs" due to incorrect use of Condition.).
A thread is said to occupy a monitor if it has entered the monitor but not yet left. Only one thread may occupy a given monitor at any moment. A monitor is also reentrant, so a thread may enter a monitor any number of times, and then must leave the same number of times. The enter and leave operations have the same synchronization semantics as the built-in Java language synchronization primitives.
A call to any of the enter methods with void return type should always be followed immediately by a try/finally block to ensure that the current thread leaves the monitor cleanly:
monitor.enter();
try {
// do things while occupying the monitor
} finally {
monitor.leave();
}
A call to any of the enter methods with boolean return type should always appear as the condition of an if statement containing a try/finally block to ensure that the current thread leaves the monitor cleanly:
if (monitor.tryEnter()) {
try {
// do things while occupying the monitor
} finally {
monitor.leave();
}
} else {
// do other things since the monitor was not available
}
synchronized and ReentrantLockThe following examples show a simple threadsafe holder expressed using synchronized,
ReentrantLock, and Monitor.
synchronizedThis version is the fewest lines of code, largely because the synchronization mechanism used
is built into the language and runtime. But the programmer has to remember to avoid a couple of
common bugs: The wait() must be inside a while instead of an if, and
notifyAll() must be used instead of notify() because there are two different
logical conditions being awaited.
public class SafeBox<V> {
private V value;
public synchronized V get() throws InterruptedException {
while (value == null) {
wait();
}
V result = value;
value = null;
notifyAll();
return result;
}
public synchronized void set(V newValue) throws InterruptedException {
while (value != null) {
wait();
}
value = newValue;
notifyAll();
}
}
ReentrantLockThis version is much more verbose than the synchronized version, and still suffers
from the need for the programmer to remember to use while instead of if. However,
one advantage is that we can introduce two separate Condition objects, which allows us to
use signal() instead of signalAll(), which may be a performance benefit.
public class SafeBox<V> {
private V value;
private final ReentrantLock lock = new ReentrantLock();
private final Condition valuePresent = lock.newCondition();
private final Condition valueAbsent = lock.newCondition();
public V get() throws InterruptedException {
lock.lock();
try {
while (value == null) {
valuePresent.await();
}
V result = value;
value = null;
valueAbsent.signal();
return result;
} finally {
lock.unlock();
}
}
public void set(V newValue) throws InterruptedException {
lock.lock();
try {
while (value != null) {
valueAbsent.await();
}
value = newValue;
valuePresent.signal();
} finally {
lock.unlock();
}
}
}
MonitorThis version adds some verbosity around the Guard objects, but removes that same
verbosity, and more, from the get and set methods. Monitor implements the
same efficient signaling as we had to hand-code in the ReentrantLock version above.
Finally, the programmer no longer has to hand-code the wait loop, and therefore doesn't have to
remember to use while instead of if.
public class SafeBox<V> {
private V value;
private final Monitor monitor = new Monitor();
private final Monitor.Guard valuePresent = monitor.newGuard(() -> value != null);
private final Monitor.Guard valueAbsent = monitor.newGuard(() -> value == null);
public V get() throws InterruptedException {
monitor.enterWhen(valuePresent);
try {
V result = value;
value = null;
return result;
} finally {
monitor.leave();
}
}
public void set(V newValue) throws InterruptedException {
monitor.enterWhen(valueAbsent);
try {
value = newValue;
} finally {
monitor.leave();
}
}
}
| Modifier and Type | Class and Description |
|---|---|
| public abstract static class | Monitor.
A boolean condition for which a thread may wait. |
| Modifier and Type | Field and Description |
|---|---|
| private Monitor. | activeGuards
The guards associated with this monitor that currently have waiters ( |
| private final boolean | fair
Whether this monitor is fair. |
| private final ReentrantLock | lock
The lock underlying this monitor. |
| Access | Constructor and Description |
|---|---|
| public | |
| public | Monitor(boolean
whether this monitor should use a fair ordering policy rather than a non-fair (but
fast) one fair)Creates a monitor with the given ordering policy. |
| Modifier and Type | Method and Description |
|---|---|
| private void | |
| private boolean | awaitNanos(Monitor.
Caller should check before calling that guard is not satisfied. |
| private void | |
| private void | beginWaitingFor(Monitor.
Records that the current thread is about to wait on the specified guard. |
| private void | endWaitingFor(Monitor.
Records that the current thread is no longer waiting on the specified guard. |
| public void | |
| public boolean | |
| public boolean | |
| public boolean | |
| public boolean | |
| public boolean | |
| public boolean | Returns: whether the monitor was entered, which guarantees that the guard is now satisfiedEnters this monitor if the guard is satisfied. |
| public boolean | Returns: whether the monitor was entered, which guarantees that the guard is now satisfiedEnters this monitor if the guard is satisfied. |
| public boolean | Returns: whether the monitor was entered, which guarantees that the guard is now satisfiedEnters this monitor if the guard is satisfied. |
| public void | |
| public boolean | |
| public boolean | Returns: whether the monitor was enteredEnters this monitor. |
| public void | |
| public boolean | |
| public boolean | |
| public void | |
| public boolean | Returns: whether the monitor was entered, which guarantees that the guard is now satisfiedEnters this monitor when the guard is satisfied. |
| public boolean | Returns: whether the monitor was entered, which guarantees that the guard is now satisfiedEnters this monitor when the guard is satisfied. |
| public int | getOccupiedDepth()
Returns the number of times the current thread has entered this monitor in excess of the number of times it has left. |
| public int | |
| public int | getWaitQueueLength(Monitor.
Returns an estimate of the number of threads waiting for the given guard to become satisfied. |
| public boolean | |
| public boolean | |
| public boolean | hasWaiters(Monitor.
Queries whether any threads are waiting for the given guard to become satisfied. |
| private static long | |
| public boolean | |
| public boolean | |
| public boolean | isOccupiedByCurrentThread()
Returns whether the current thread is occupying this monitor (has entered more times than it has left). |
| private boolean | isSatisfied(Monitor.
Exactly like guard.isSatisfied(), but in addition signals all waiting threads in the (hopefully unlikely) event that isSatisfied() throws. |
| public void | |
| public Monitor. | newGuard(final BooleanSupplier
the new guard's boolean condition (see isSatisfied)isSatisfied())Creates a new guard for this monitor. |
| private static long | remainingNanos(long startTime, long timeoutNanos)
Returns the remaining nanos until the given timeout, or 0L if the timeout has already elapsed. |
| private void | |
| private void | |
| private static long | toSafeNanos(long time, TimeUnit unit)
Returns unit.toNanos(time), additionally ensuring the returned value is not at risk of overflowing or underflowing, by bounding the value between 0 and (Long.MAX_VALUE / 4) * 3. |
| public boolean | Returns: whether the monitor was enteredEnters this monitor if it is possible to do so immediately. |
| public boolean | Returns: whether the monitor was entered, which guarantees that the guard is now satisfiedEnters this monitor if it is possible to do so immediately and the guard is satisfied. |
| public void | |
| public boolean | |
| public boolean | |
| public void | |
| public boolean | Returns: whether the guard is now satisfiedWaits for the guard to be satisfied. |
| public boolean | Returns: whether the guard is now satisfiedWaits for the guard to be satisfied. |
| activeGuards | back to summary |
|---|---|
| private Monitor. The guards associated with this monitor that currently have waiters (
| |
| fair | back to summary |
|---|---|
| private final boolean fair Whether this monitor is fair. | |
| lock | back to summary |
|---|---|
| private final ReentrantLock lock The lock underlying this monitor. | |
| Monitor | back to summary |
|---|---|
| public Monitor() Creates a monitor with a non-fair (but fast) ordering policy. Equivalent to | |
| Monitor | back to summary |
|---|---|
| public Monitor(boolean fair) Creates a monitor with the given ordering policy.
| |
| await | back to summary |
|---|---|
private void await(Monitor.
| |
| awaitNanos | back to summary |
|---|---|
| private boolean awaitNanos(Monitor. Caller should check before calling that guard is not satisfied.
| |
| awaitUninterruptibly | back to summary |
|---|---|
private void awaitUninterruptibly(Monitor.
| |
| beginWaitingFor | back to summary |
|---|---|
| private void beginWaitingFor(Monitor. Records that the current thread is about to wait on the specified guard.
| |
| endWaitingFor | back to summary |
|---|---|
| private void endWaitingFor(Monitor. Records that the current thread is no longer waiting on the specified guard.
| |
| enter | back to summary |
|---|---|
| public void enter() Enters this monitor. Blocks indefinitely. | |
| enter | back to summary |
|---|---|
| public boolean enter(Duration time) Enters this monitor. Blocks at most the given time.
| |
| enter | back to summary |
|---|---|
| public boolean enter(long time, TimeUnit unit) Enters this monitor. Blocks at most the given time.
| |
| enterIf | back to summary |
|---|---|
| public boolean enterIf(Monitor. Enters this monitor if the guard is satisfied. Blocks indefinitely acquiring the lock, but does not wait for the guard to be satisfied.
| |
| enterIf | back to summary |
|---|---|
| public boolean enterIf(Monitor. Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the lock, but does not wait for the guard to be satisfied.
| |
| enterIf | back to summary |
|---|---|
| public boolean enterIf(Monitor. Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the lock, but does not wait for the guard to be satisfied.
| |
| enterIfInterruptibly | back to summary |
|---|---|
| public boolean enterIfInterruptibly(Monitor. Enters this monitor if the guard is satisfied. Blocks indefinitely acquiring the lock, but does not wait for the guard to be satisfied, and may be interrupted.
| |
| enterIfInterruptibly | back to summary |
|---|---|
| public boolean enterIfInterruptibly(Monitor. Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the lock, but does not wait for the guard to be satisfied, and may be interrupted.
| |
| enterIfInterruptibly | back to summary |
|---|---|
| public boolean enterIfInterruptibly(Monitor. Enters this monitor if the guard is satisfied. Blocks at most the given time acquiring the lock, but does not wait for the guard to be satisfied, and may be interrupted.
| |
| enterInterruptibly | back to summary |
|---|---|
| public void enterInterruptibly() throws InterruptedException Enters this monitor. Blocks indefinitely, but may be interrupted.
| |
| enterInterruptibly | back to summary |
|---|---|
| public boolean enterInterruptibly(Duration time) throws InterruptedException Enters this monitor. Blocks at most the given time, and may be interrupted.
| |
| enterInterruptibly | back to summary |
|---|---|
| public boolean enterInterruptibly(long time, TimeUnit unit) throws InterruptedException Enters this monitor. Blocks at most the given time, and may be interrupted.
| |
| enterWhen | back to summary |
|---|---|
| public void enterWhen(Monitor. Enters this monitor when the guard is satisfied. Blocks indefinitely, but may be interrupted.
| |
| enterWhen | back to summary |
|---|---|
| public boolean enterWhen(Monitor. Enters this monitor when the guard is satisfied. Blocks at most the given time, including both the time to acquire the lock and the time to wait for the guard to be satisfied, and may be interrupted.
| |
| enterWhen | back to summary |
|---|---|
| public boolean enterWhen(Monitor. Enters this monitor when the guard is satisfied. Blocks at most the given time, including both the time to acquire the lock and the time to wait for the guard to be satisfied, and may be interrupted.
| |
| enterWhenUninterruptibly | back to summary |
|---|---|
| public void enterWhenUninterruptibly(Monitor. Enters this monitor when the guard is satisfied. Blocks indefinitely. | |
| enterWhenUninterruptibly | back to summary |
|---|---|
| public boolean enterWhenUninterruptibly(Monitor. Enters this monitor when the guard is satisfied. Blocks at most the given time, including both the time to acquire the lock and the time to wait for the guard to be satisfied.
| |
| enterWhenUninterruptibly | back to summary |
|---|---|
| public boolean enterWhenUninterruptibly(Monitor. Enters this monitor when the guard is satisfied. Blocks at most the given time, including both the time to acquire the lock and the time to wait for the guard to be satisfied.
| |
| getOccupiedDepth | back to summary |
|---|---|
| public int getOccupiedDepth() Returns the number of times the current thread has entered this monitor in excess of the number of times it has left. Returns 0 if the current thread is not occupying this monitor. | |
| getQueueLength | back to summary |
|---|---|
| public int getQueueLength() Returns an estimate of the number of threads waiting to enter this monitor. The value is only an estimate because the number of threads may change dynamically while this method traverses internal data structures. This method is designed for use in monitoring of the system state, not for synchronization control. | |
| getWaitQueueLength | back to summary |
|---|---|
| public int getWaitQueueLength(Monitor. Returns an estimate of the number of threads waiting for the given guard to become satisfied. Note that because timeouts and interrupts may occur at any time, the estimate serves only as an upper bound on the actual number of waiters. This method is designed for use in monitoring of the system state, not for synchronization control. | |
| hasQueuedThread | back to summary |
|---|---|
| public boolean hasQueuedThread(Thread thread) Queries whether the given thread is waiting to enter this monitor. Note that because
cancellations may occur at any time, a | |
| hasQueuedThreads | back to summary |
|---|---|
| public boolean hasQueuedThreads() Returns whether any threads are waiting to enter this monitor. Note that because cancellations
may occur at any time, a | |
| hasWaiters | back to summary |
|---|---|
| public boolean hasWaiters(Monitor. Queries whether any threads are waiting for the given guard to become satisfied. Note that
because timeouts and interrupts may occur at any time, a | |
| initNanoTime | back to summary |
|---|---|
| private static long initNanoTime(long timeoutNanos) Returns System.nanoTime() unless the timeout has already elapsed. Returns 0L if and only if the timeout has already elapsed. | |
| isFair | back to summary |
|---|---|
| public boolean isFair() Returns whether this monitor is using a fair ordering policy. | |
| isOccupied | back to summary |
|---|---|
| public boolean isOccupied() Returns whether this monitor is occupied by any thread. This method is designed for use in monitoring of the system state, not for synchronization control. | |
| isOccupiedByCurrentThread | back to summary |
|---|---|
| public boolean isOccupiedByCurrentThread() Returns whether the current thread is occupying this monitor (has entered more times than it has left). | |
| isSatisfied | back to summary |
|---|---|
| private boolean isSatisfied(Monitor. Exactly like guard.isSatisfied(), but in addition signals all waiting threads in the (hopefully unlikely) event that isSatisfied() throws.
| |
| leave | back to summary |
|---|---|
| public void leave() Leaves this monitor. May be called only by a thread currently occupying this monitor. | |
| newGuard | back to summary |
|---|---|
| public Monitor. Creates a new guard for this monitor.
| |
| remainingNanos | back to summary |
|---|---|
| private static long remainingNanos(long startTime, long timeoutNanos) Returns the remaining nanos until the given timeout, or 0L if the timeout has already elapsed. Caller must have previously sanitized timeoutNanos using toSafeNanos. | |
| signalAllWaiters | back to summary |
|---|---|
| private void signalAllWaiters() Signals all threads waiting on guards.
| |
| signalNextWaiter | back to summary |
|---|---|
| private void signalNextWaiter() Signals some other thread waiting on a satisfied guard, if one exists. We manage calls to this method carefully, to signal only when necessary, but never losing a signal, which is the classic problem of this kind of concurrency construct. We must signal if the current thread is about to relinquish the lock and may have changed the state protected by the monitor, thereby causing some guard to be satisfied. In addition, any thread that has been signalled when its guard was satisfied acquires the responsibility of signalling the next thread when it again relinquishes the lock. Unlike a normal Condition, there is no guarantee that an interrupted thread has not been signalled, since the concurrency control must manage multiple Conditions. So this method must generally be called when waits are interrupted. On the other hand, if a signalled thread wakes up to discover that its guard is still not satisfied, it does *not* need to call this method before returning to wait. This can only happen due to spurious wakeup (ignorable) or another thread acquiring the lock before the current thread can and returning the guard to the unsatisfied state. In the latter case the other thread (last thread modifying the state protected by the monitor) takes over the responsibility of signalling the next waiter. This method must not be called from within a beginWaitingFor/endWaitingFor block, or else the current thread's guard might be mistakenly signalled, leading to a lost signal.
| |
| toSafeNanos | back to summary |
|---|---|
| private static long toSafeNanos(long time, TimeUnit unit) Returns unit.toNanos(time), additionally ensuring the returned value is not at risk of overflowing or underflowing, by bounding the value between 0 and (Long.MAX_VALUE / 4) * 3. Actually waiting for more than 219 years is not supported! | |
| tryEnter | back to summary |
|---|---|
| public boolean tryEnter() Enters this monitor if it is possible to do so immediately. Does not block. Note This method disregards the fairness setting of this monitor.
| |
| tryEnterIf | back to summary |
|---|---|
| public boolean tryEnterIf(Monitor. Enters this monitor if it is possible to do so immediately and the guard is satisfied. Does not block acquiring the lock and does not wait for the guard to be satisfied. Note This method disregards the fairness setting of this monitor.
| |
| waitFor | back to summary |
|---|---|
| public void waitFor(Monitor. Waits for the guard to be satisfied. Waits indefinitely, but may be interrupted. May be called only by a thread currently occupying this monitor.
| |
| waitFor | back to summary |
|---|---|
| public boolean waitFor(Monitor. Waits for the guard to be satisfied. Waits at most the given time, and may be interrupted. May be called only by a thread currently occupying this monitor.
| |
| waitFor | back to summary |
|---|---|
| public boolean waitFor(Monitor. Waits for the guard to be satisfied. Waits at most the given time, and may be interrupted. May be called only by a thread currently occupying this monitor.
| |
| waitForUninterruptibly | back to summary |
|---|---|
| public void waitForUninterruptibly(Monitor. Waits for the guard to be satisfied. Waits indefinitely. May be called only by a thread currently occupying this monitor. | |
| waitForUninterruptibly | back to summary |
|---|---|
| public boolean waitForUninterruptibly(Monitor. Waits for the guard to be satisfied. Waits at most the given time. May be called only by a thread currently occupying this monitor.
| |
| waitForUninterruptibly | back to summary |
|---|---|
| public boolean waitForUninterruptibly(Monitor. Waits for the guard to be satisfied. Waits at most the given time. May be called only by a thread currently occupying this monitor.
| |
Guard is associated with a single
Monitor. The monitor may check the guard at arbitrary times from any thread occupying
the monitor, so code should not be written to rely on how often a guard might or might not be
checked.
If a Guard is passed into any method of a Monitor other than the one it is
associated with, an IllegalMonitorStateException is thrown.
| Modifier and Type | Field and Description |
|---|---|
| pack-priv final Condition | |
| pack-priv final Monitor | |
| pack-priv Monitor. | next
The next active guard |
| pack-priv int |
| Modifier and Type | Method and Description |
|---|---|
| public abstract boolean |
| condition | back to summary |
|---|---|
| pack-priv final Condition condition | |
| monitor | back to summary |
|---|---|
| pack-priv final Monitor monitor
| |
| next | back to summary |
|---|---|
| pack-priv Monitor. The next active guard
| |
| waiterCount | back to summary |
|---|---|
pack-priv int waiterCount
| |
| Guard | back to summary |
|---|---|
| protected Guard(Monitor monitor) | |
| isSatisfied | back to summary |
|---|---|
| public abstract boolean isSatisfied() Evaluates this guard's boolean condition. This method is always called with the associated monitor already occupied. Implementations of this method must depend only on state protected by the associated monitor, and must not modify that state. | |