Tuesday, February 20, 2007

Five Categories of Thread Safety

In his Effective Java, Joshua Bloch described five categories of thread safety: immutable, thread-safe, conditionally thread-safe, thread-compatible, and thread-hostile.
  • Immutable objects are guaranteed to be thread-safe, and never require additional synchronization. Because an immutable object's externally visible state never changes, as long as it is constructed correctly, it can never be observed to be in an inconsistent state. Most of the basic value classes in the Java class libraries, such as Integer, String, and BigInteger, are immutable.
  • Thread-safe classes are safe not only for single call, but also for multiple calls combined. They will need no additional synchronzation from their callers. This thread-safety guarantee is a strong one -- many classes, like Hashtable or Vector, will fail to meet this stringent definition.
  • Conditionally thread-safe classes are those for which each individual operation may be thread-safe, but certain sequences of operations may require external synchronization. The most common example of conditional thread safety is traversing an iterator returned from Hashtable or Vector -- the fail-fast iterators returned by these classes assume that the underlying collection will not be mutated while the iterator traversal is in progress. To ensure that other threads will not mutate the collection during traversal, the iterating thread should be sure that it has exclusive access to the collection for the entirety of the traversal. Typically, exclusive access is ensured by synchronizing on a lock -- and the class's documentation should specify which lock that is (typically the object's intrinsic monitor).
  • Thread-compatible classes are not thread-safe, but can be used safely in concurrent environments by using synchronization appropriately. This might mean surrounding every method call with a synchronized block or creating a wrapper object where every method is synchronized (like Collections.synchronizedList()). Or it might mean surrounding certain sequences of operations with a synchronized block. To maximize the usefulness of thread-compatible classes, they should not require that callers synchronize on a specific lock, just that the same lock is used in all invocations. Doing so will enable thread-compatible objects held as instance variables in other thread-safe objects to piggyback on the synchronization of the owning object. Many common classes are thread-compatible, such as the collection classes ArrayList and HashMap, java.text.SimpleDateFormat, or the JDBC classes Connection and ResultSet.
  • Thread-hostile classes are those that cannot be rendered safe to use concurrently, regardless of what external synchronization is invoked. Thread hostility is rare, and typically arises when a class modifies static data that can affect the behavior of other classes that may execute in other threads. An example of a thread-hostile class would be one that calls System.setOut().

No comments: