{@code}if (monitor.tryEnter()) try { // do things while occupying the monitor } finally { monitor.leave(); } } else { // do other things since the monitor was not available }}
The following examples show a simple threadsafe holder expressed using {@code synchronized}, {@link ReentrantLock}, and {@code Monitor}.
This 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 {@code wait()} must be inside a {@code while} instead of an {@code if}, and {@code notifyAll()} must be used instead of {@code notify()} because there are two differentlogical conditions being awaited.
{@code}public class SafeBoxprivate 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(); } }}
This version is much more verbose than the {@code synchronized} version, and still suffersfrom the need for the programmer to remember to use {@code while} instead of {@code if}. However, one advantage is that we can introduce two separate {@code Condition} objects, whichallows us to use {@code signal()} instead of {@code signalAll()}, which may be a performance benefit.
{@code}public class SafeBoxprivate final ReentrantLock lock = new ReentrantLock(); private final Condition valuePresent = lock.newCondition(); private final Condition valueAbsent = lock.newCondition(); private V value; 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(); } } }}
This version adds some verbosity around the {@code Guard} objects, but removes that sameverbosity, and more, from the {@code get} and {@code set} methods. {@code Monitor} implements thesame efficient signaling as we had to hand-code in the {@code ReentrantLock} version above.Finally, the programmer no longer has to hand-code the wait loop, and therefore doesn't have to remember to use {@code while} instead of {@code if}.
{@code}public class SafeBox@author Justin T. Sampson @since Guava release 10private final Monitor monitor = new Monitor(); private final Monitor.Guard valuePresent = new Monitor.Guard(monitor) { public boolean isSatisfied() { return value != null; } }; private final Monitor.Guard valueAbsent = new Monitor.Guard(monitor) { public boolean isSatisfied() { return value == null; } }; private V value; 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(); } } }}
|
|
|
|
|
|
|
|