Chapter 2 Multitasking Safety 11
Multithread Safety
The most obvious problem with the interface defined in CODE EXAMPLE 2-3 is that it
is not thread-safe. A single Java platform thread (Java thread) calling the APIs can
certainly use it effectively, but if another thread attempts to use the API, things
almost certainly break. For example, one thread might call setTime(). Another
thread might be scheduled and issue a call to setTime() with a different value.
When the first thread calls cook(), the cook time used is actually the cook time set
by the second thread. When the second thread calls cook(), the cooking operation
initiated by the first thread might still be going on, which gives rise to an error.
A reasonable way to make this interface thread safe is to introduce mutual exclusion,
so that one thread can be assured that no other threads are interfering with its
operation. This ensures that intermediate state (such as cook time) is not altered
between the setup calls and the cook() call. It also ensures that only one cook()
operation can be processed at once, a restriction imposed by the underlying native
API.
Because exclusion is required around multiple calls to this interface, making the
methods synchronized is insufficient. Therefore, introduce a lock() and unlock()
protocol that clients are required to use around their calls to other methods. Each
native method is wrapped with a Java method that checks for the proper lock state
before proceeding to call the native method.
CODE EXAMPLE 2-4 Introducing a Locking Mechanism for Thread Safety
public class Microwave {
private static boolean initialized = false;
private static Thread owner = null;
public static synchronized void lock()
throws InterruptedException {
while (owner != null) {
wait();
}
owner = Thread.currentThread();
if (!initialized) {
init();
initialized = true;
}
}
public static synchronized unlock() {
owner = null;
notifyAll();
}