Monday, November 26, 2012

Part VIII - Effective Java - Threads

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.

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.

No comments: