Friday, August 17, 2007

How Java Static Fields (AKA Class Variables) Break Thread Confinement and Lead to Concurrency Bugs.

Java static fields are shared between all instances of a class for a given class loader. One common use of static fields is to declare constants via the static final syntax.

Unfortunately, static final fields don’t ensure that the variable will be constant or immutable. It only guarantees that the field will be shared between all instances of the class for a given class loader (i.e. static) and that, apart from special cases involving reflection and deserialization (see JLS v3 17.5.3), it will not be reinitialized (i.e. final). In particular, there are two situations to consider corresponding to the major type categories in Java; primitive types (e.g. int, boolean, etc.) and reference types (e.g. arrays, interfaces, and classes).

Once a primitive is declared static final and it is assigned a value, there is no need to worry about it anymore. It will never change (except in unusual circumstances, see JLS v3 17.5.3).

For reference types, this is a different story. If the static final reference type is a mutable class (e.g. HashMap), it cannot be reinitialized, but the instance of that class can change after construction via the HashMap put method, for example.

Listing 1

public class Foobar{
//Mutable class variable.
private static final Map mutableField = new HashMap();
public Foobar() {}
public void qwerty(){
// Code to mutate the mutableField via put method.
}
}

And therein that static mutable field lies our thread safety concerns. If there are a couple threads floating around both using instances of that same class via the qwerty method from listing 1 for example, they can step on each other via their mutable class variable. Worse, the static mutable can be sitting "far away" from the programmer’s code in an open source library and a multi-threaded application can indirectly hammer on that static mutable possibly leaving it inconsistent and broken. The static final class variable can even be private. If it is affected by the instances of the class from multi-threaded application, it can be subject to thread safety concerns.

Even worse still, there are many ways to refactor the class referenced by static field to be immutable thereby achieving thread safety, but there is no way to make the contents of an array type immutable in Java. (This is yet another reason to consider arrays a deprecated type -- see O’Reilly’s Java Generics 6.9.)

This is not an academic point. A common way of ensuring thread safety is to have objects visible only from one thread. This is known as thread confinement and is common to client-server request-based architectures (see CPJ 2.3). The problem is that static fields break thread confinement and encapsulation because the same class variable can be accessed from multiple instances of the class, and if it is mutable is subject to race conditions in a multi-threaded environment.

This discussion may seem obvious, but I do not see this fact explicitly stated in either Java Concurrency in Practice or Concurrency in Java. Don’t get me wrong. These books are masterpieces of modern software engineering literature and I have immense admiration and respect for the authors, but I did not see any concrete mention of this danger with static mutable variables. In fact, to fix these problems I would recommend reading these books. Describing solutions and workarounds would definitely go beyond the scope of this blog entry.

Once again, as detailed in Java Concurrency in Practice, it is the shared mutable field that endangers thread safety. But in the case of static fields, the shared mutable is shared via the static modifier rather than one instance of the class shared by multiple threads.