Not Thread Safe Java Code
Reusing the previous example, a race condition exists on a Java class that writes and reads shared data.
public class SomeClass {
private volatile boolean flag = 0;
// Invoked by multiple threads
public void doStuff() {
flag = true;
if(flag!=true) {
barf(); // could end up here
}
flag = false;
}
}
In the previous example section, synchronization and the @ThreadSafe annotation were discussed as possible way to fix the race condition. Another approach is to declare the method not thread safe using the @NotThreadSafe annotation.
Example: Declaring a Method NotThreadSafe
By declaring a method @NotThreadSafe, you are documenting to any client code that the caller of the method is responsible for ensuring proper synchronization. In effect, you are simplifying the implementation of an API at the burden of the invoking client. In some situations, this trade off fullfills design requirements in a more elegant fashion than simply requiring an API to be thread safe.
A real world example of a thread unsafe library is the Java collections API (e.g. java.util.ArrayList, HashMap) which are NotThreadSafe out of the box for fast performance and simplicity. Users of ArrayList and HashMap are responsible for ensure proper synchronization through a variety of techniques.
CheckThread will not report any errors when inspecting the following Java code.
import org.checkthread.annotations.NotThreadSafe;
public class SomeClass {
private volatile boolean flag = 0;
// Invoked by multiple threads
@NotThreadSafe
public void doStuff() {
flag = true;
if(flag!=true) {
barf();
}
flag = false;
}
}
Example: Invoking a NotThreadSafe Method
Invoking a @NotThreadSafe method simply means that the client code is responsible for ensuring property synchronization. What data should the client synchronize on? That information should be conveyed in the JavaDoc. Note: A future goal with CheckThread is to establish a convention for expressing the synchronization target requirements within theNotThreadSafe annotation.
In the previous example, the synchronization scope was the instance. In other words, the client must synchronize on the object instance or some aggregate owner of the object instance before calling the thread unsafe method.
import org.checkthread.annotations.ThreadSafe;
public class SomeClientClass {
private SomeClass someClass = new SomeClass();
// Invoked by multiple threads
@ThreadSafe
public void doThreadSafeStuff() {
// OKAY: CheckThread will not error.
synchronized(someClass) {
someClass.doStuff();
}
}
}
Other possible ways to invoke a thread unsafe method include synchronizing on an aggregate (e.g. "this" in the previous example) or using a synrchronization wrapper available for the Java 1.5 collections package.