Threads
Write
code using synchronized, wait, notify, or notifyAll,
to protect against concurrent access problems and to
communicate between threads. Define the interaction
between threads and between threads and object locks
when executing synchronized, wait, notify, or
notifyAll.
Synchronization:
When two or more threads
need access to a shared resource, they need some way
to ensure that the resource will be used only by one
thread at a time. The process by which this is ensured
is called Synchronization.
Key to synchronization
is the concept of the monitor (also called Semaphore).
A monitor is an object that is used as a mutually
exclusive lock, or mutex. Only one thread can own a
monitor at a given time. When a thread acquires a
lock, it is said to have entered the monitor. All
other threads attempting to enter the locked monitor
will be suspended until the first thread exits the
monitor. A thread that owns a monitor can reenter the
same monitor if it so desires. There are two ways to
synchronize your code:
Synchronizing is easy in
Java because all objects have their own monitor
associated with them. To enter an object’s monitor,
just call a method that has been modified with the
synchronized keyword.
While a thread is inside a synchronized method, all
other threads that try to call it ( or any other
synchronized method) on the same instance have to
wait. To exit the monitor and relinquish control of
the object to the next waiting thread, the owner of
the monitor simply returns from the synchronized
method.
When there is no
synchronization, nothing exists to stop all the
threads from calling the same method on the same
object at the same time. This is known as a race
condition, because the threads are vying with each
other to complete the method. In most situations, a
race condition is less predictable, because you cannot
be sure when the context switch will occur. This can
cause a program to run right one time and wrong the
next.
To fix this problem you
must serialize access to a method. That is, you must
restrict its access to only one thread at a time. To
do this, qualify the method with ‘synchronized’ keyword. Anytime
that you have a method, or a group of methods that
manipulate the internal state of an object in a
multi-threaded situation, you should use the ‘synchronized’ keyword to guard
the state from race conditions. Once a thread enters
any synchronized method on an instance, no other
thread can enter any other synchronized method on the
same instance. However, non- synchronized method on
that instance will continue to be callable.
If you want to
synchronize access to objects of a class that was not
designed for multi-threaded access i.e. the class does
not use synchronized methods or if you do not access
to the source code of the class, then simply put calls
to the methods defined by this class inside a
synchronized block
synchronized ( object){
// statements to be
synchronized.
}
Here object is a
reference to the object being synchronized. If you
want to synchronize only a single statement, curly
braces are not needed. A
synchronized block ensures that a call to a
method that is a member of object occurs only after
the current thread has successfully entered object’s
monitor.
Inter-thread
communication:
Multithreading replaces
event loop programming by dividing your tasks into
discreet and logical units. Threads also provide a
secondary benefit: they do away with polling. Polling
is usually implemented by a loop that is used to check
some condition repeatedly. Once the condition is true,
appropriate action is taken. This wastes CPU time.
To avoid polling, Java
includes an elegant inter-process communication via
wait(), notify() and notifyAll(). These methods are
implemented as final
methods in Object, so all classes have them. All these
three methods can be called only from within a
synchronized method.
The method wait() tells
the calling thread to give up the monitor and go to
sleep until some other thread enters the monitor and
calls notify(). Additional forms of wait() exist that
allow you to specify a period of time to wait.
The method notify()
wakes up the first thread that called wait() on the
same object.
The method notifyAll()
wakes up all the threads that called wait() on the
same object. The highest priority thread will run
first.
Deadlock
A special type of error
in multitasking is deadlock, which occurs when two
threads have a circular dependency on a pair of
synchronized objects. For example, suppose one thread
enters the monitor on object x and another thread enters
the monitor on object y. If the thread in x tries to
call any synchronized method on y, it will block as
expected. However, if the thread in y, in turn, tries
to call any synchronized method on x, the thread waits
forever, because to access x, it would have to release
its own lock on y so that the first thread could
complete.
Deadlock is a difficult
error to debug because:
-
In general, it occurs only rarely,
when the two threads time-slice in just the right
way.
-
It may involve more than two threads and two
synchronized objects.
|