Thread Synchronization
The essential idea is that if we declare a method synchronized, then other synchronized methods cannot be simultaneously called on the same object.
- If multiple threads concurrently try to call the synchronized function, only one thread at a time will actually execute it; the others will effectively "queue up" until it's their turn
- Synchronizing also crucially means that the result calculated in one thread is visible to other threads calling the method.
- Whether via the synchronized keyword or an explicit Java Lock, data sharing with object locking is a cooperative process: that is, all code accessing (reading or writing) the dependent data must synchronize.
- Synchronize is implemented using a concept called monitors.
- Each object in Java is associated with a monitor, which a thread can lock or unlock.
- Only one thread at a time may hold a lock on a monitor.
synchronized(objectidentifier) {
// Access shared variables and other shared resources
}
objectidentifier
is a reference to an object whose lock associates with the monitor that the synchronized statement represents.
Inter-thread Communication
Inter thread communication is important when you develop an application where two or more threads exchange some information. ||| |---|---| public void wait() | Causes the current thread to wait until another thread invokes the notify(). public void notify()| Wakes up a single thread that is waiting on this object's monitor.| public void notifyAll()|Wakes up all the threads that called wait( ) on the same object.
These methods have been implemented as final methods in Object, so they are available in all the classes.
All three methods can be called only from within a synchronized context.
Why wait()
,notify()
, notifyAll()
must be called inside a synchronized method/block?
- An object's method without qualifed by the keyword synchronized can be invoked by any number of threads at any time, the lock is ignored.
The synchronized method of an object, one and only one thread, who owns the lock of that object, can be permitted to run that method at any time; i.e. a synchronized method is mutually exclusive.
- If, at the time of invocation, another thread owns the lock, then the calling thread will be put in the Blocked state and is added to the entry queue.
When a thread running in a synchronized method of an object is calling the
wait()
method of the same object, that thread releases the lock of the object and is added to that object's waiting queue.- As long as it's there, it sits idle.
- Note also that wait() forces the thread to release its lock. This means that it must own the lock of an object before calling the wait() method of that (same) object. Hence the thread must be in one of the object's synchronized methods or synchronized block before calling wait().
When a thread invokes an object's notify() or notifyAll() method, one (an arbitrary thread) or all of the threads in its waiting queue are removed from the waiting queue to the entry queue. They then actively contend for the object's lock, and the one that gets the lock goes on to execute. If no threads are waiting in the waiting queue, then notify() and notifyAll() have no effect. Before calling the notify() or notifyAll() method of an object, a thread must own the lock of the object. Hence it must be in one of the object's synchronized methods or synchronized block.
A thread in the waiting queue of an object can run again only when some other thread calls the notify() (or the notifyAll) method of the same object.
The reason to call wait() is that the thread does not want to execute a block of code until a particular state to be achieved. It wants to wait until a particular state to be achieved. The reason to call notify() or notifyAll() method is that the thread will signal others that "a particular state has been achieved". The state is a communication channel between threads and it must be shared mutable state.
For example, one thread read data from a buffer and one thread write data into buffer. The reading data thread needs to wait until the writing data thread completly write a block data into the buffer. The wirting data thread needs to wait until the reading data thread completly read the data from the buffer. If wait(), notify(), and notifyAll() methods can be called by a ordinary method , the reading thread calls wait() and the thread is being added to waiting queue . At just the same moment, the writing thread calls notify() to signal the condition changes. The reading thread misses the change and waits forever. Hence, they must be called inside a synchronized method or block which is mutually exclusive.
Thread interruption
Interruption is a mechanism whereby a thread that is waiting (or sleeping) can be made to prematurely stop waiting.
- The
InterruptedException
is thrown by theThread.sleep()
method, and in fact by a few other core library methods that can "block", principally:Object.wait()
, part of the wait/notify mechanism;Thread.join()
, that makes the current thread wait for another thread to complete;Proess.waitFor()
, which lets us wait for an external process (started from our Java application) to terminate;
- In general,
InterruptedException
is thrown when another thread interrupts the thread calling the blocking method. The other thread interrupts the blocking/sleeping thread by callinginterrupt()
on it - Incidentally, it is important not to confuse thread interruption with either
- software interrupts (where the CPU automatically interrupts the current instruction flow in order to call a registered piece of code periodically— as in fact happens to drive the thread scheduler)
- hardware interrupts (where the CPU automatically performs a similar task in response to some hardware signal).