The purpose of thread signaling is to enable threads to send signals to each other. It enables threads to wait for signals from other threads. For instance, a thread B might wait for a signal from thread A indicating that data is ready to be processed.
Signaling via Shared Objects
A thread can send signals to each other is by setting the signal values in some shared object variable (Busy waiting). Thread A may set the boolean member variable hasDataToProcess to true from inside a synchronized block, and thread B may read the hasDataToProcess member variable, also inside a synchronized block. Thread A and B must have a reference to a shared MySignal instance for the signaling to work. Thread B is waiting for a signal from thread A which causes hasDataToProcess() to return true.
public class Signal{ protected boolean hasDataToProcess = false; public synchronized boolean hasDataToProcess(){ return this.hasDataToProcess; } public synchronized void setHasDataToProcess(boolean hasData){ this.hasDataToProcess = hasData; } }
wait(), notify() and notifyAll()
Busy waiting is not a very efficient utilization of the CPU, except if the average waiting time is very small. Java has a builtin wait mechanism that enable threads to become inactive while waiting for signals. The Object class defines three methods, wait(), notify(), and notifyAll(), to facilitate this.
A thread that calls wait() on any object becomes inactive until another thread calls notify() on that object. In order to call either wait() or notify the calling thread must first obtain the lock on that object. In other words, the calling thread must call wait() or notify() from inside a synchronized block.
public class MonitorObject{ } public class WaitNotify{ MonitorObject monitorObj = new MonitorObject(); public void doWait(){ synchronized(monitorObj){ try{ monitorObj.wait(); } catch(InterruptedException e){...} } } public void doNotify(){ synchronized(monitorObj){ monitorObj.notify(); } } }
The waiting thread would call doWait(), and the notifying thread would call doNotify(). When a thread calls notify() on an object, one of the threads waiting on that object are awakened and allowed to execute. There is also a notifyAll() method that will wake all threads waiting on a given object. Once a thread calls wait() (doWait() here ) it releases the lock it holds on the monitor object. This allows other threads to call wait() or notify() too, since these methods must be called from inside a synchronized block.
Once a thread is awakened it must reobtain the lock on the monitor object before it can exit the wait() call, because the wait call is nested inside a synchronized block. If multiple threads are awakened using notifyAll() only one awakened thread at a time can exit the wait() method, since each thread must obtain the lock on the monitor object in turn before exiting wait().