This is the eighth post in the series of postings based on the book Effective Java by Joshua Bloch. In the previous post we read about best practices in Exception handling in Java.
This post covers the best practices in writing threaded applications. Threads are not understood properly by many and if not used properly can lead to a variety of problems. It is important to understand and use the best practices outlined here.
This post covers the best practices in writing threaded applications. Threads are not understood properly by many and if not used properly can lead to a variety of problems. It is important to understand and use the best practices outlined here.
Synchronized access to shared mutable data
It is better to use an available library which is thread
safe rather than trying to write one’s own thread safe classes.
When a method that mutates the object can be accessed by
more than one thread at a time it is better to synchronize the method rather
than except it to work.
Usage of volatile to overcome the problems of
synchronization is questionable and do not use it.
Avoid Excessive Synchronization
While synchronization is necessary avoid excessive
synchronization. Excessive synchronization will lead to poor performance and in
worst case scenarios lead to race conditions or deadlocks.
To safeguard against deadlocks never invoke an abstract
method in a synchronized block.
To keep performance acceptable, do as little work as
possible inside the synchronized block.
Take as granular a lock as possible.
Never invoke wait outside a loop
The object.wait method is used to make a thread wait for
some condition. It must be invoked inside a synchronized region that locks the
object on which it is invoked. The right use of wait is as follows:
synchronized(obj) {
while() {
obj.wait();
}
//Perform action
appropriate to condition
}
Note that the condition needs to be checked before entering
the wait state. If a method enters a wait state without checking for the
condition it is not guaranteed that it will get the notify or notifyAll event
to wake it from its wait state. This will mean that the thread can go into an
hang state and never come out of it.
Don’t depend on the thread scheduler
Do not depend on the thread scheduler to stop work in a
thread and hand over control to other threads. Voluntarily stop working by
invoking an Object.wait or a Thread.sleep.
Document Thread Safety
If the user does not know if a method is thread-safe or not
then we can end up with a code which has excessive synchronization or no
synchronization and both will lead to problems in the system. One should always
specify if a method is thread safe or not. It should specify one of the
following:
1.
Immutable: This indicates that the class and its
method are thread-safe by virtue of the class being immutable.
2.
Thread-safe: Although the class is mutable the
methods have sufficient synchronization and so do not need any external
synchronization.
3.
Conditionally thread-safe: This means that the
class is thread-safe exception that there are some methods that must be invoked
in sequence without interference from other threads. Examples are Hashtable and
Vector whose iterators need to be invoked in an externally synchronized block.
4.
Thread-compatible: These are classes who are not
thread safe by themselves by can be made thread-safe by invoking methods or
series of methods of this class in a synchronized block.
5.
Thread-hostile – This means that this class
should never be used in a multi-threaded environment. No amount of
synchronization will help such classes.
Avoid Thread Groups
The concept of thread groups are obsolete and should not be
used.
In the next and the last post we will read about best practices of Serialization.
In the next and the last post we will read about best practices of Serialization.
No comments:
Post a Comment