CheckThread.org (Beta)

Thread Safety Example

Can you see a bug with the following Java code?

import java.util.*;

public class SomeClass {

private final Map<String,String> map = new HashMap<String,String>();
    
    // Invoked by multiple threads
    public void doStuff() {
        map.put("foo","bar"); 
    }
}

The comment of the doStuff() method intends to be thread safe and calls HashMap.put(...). However, the HashMap.put(...) method is not thread safe. Specifically, structural modifications to the HashMap implementation should be synchronized.

If the key "foo" already exists, it's possible this code could be thread safe, but that is a risky assumption.This code can result in a race condition or unpredictable behavior if doStuff() is invoked by more than one thread concurrently.

This type of bug can go unnoticed through visual inspection, pass unit and integration tests, but later lead to a failure when deployed to a customer site or in a production environment with specific compute resource characterisitcs. The goal with CheckThread is to catch these type of concurrency bugs at compile time.

Catching Concurrency Bugs at Compile Time

In order to catch concurrency bugs at compile time, a static analysis tool requires some machine inteprettable way of reading a method's intended thread policy. Does the implementer of an interface intend the API to be thread safe, not thread safe, or thread confined?

Thread policies are already expressed in prose within JavaDoc, but they can not be interpreted through static analysis in a simple way since the location and words very so much across the many JavaDoc library API's.

With CheckThread, a common set of annotations or XML is used to express the thread policy for a method or class. In doing so, "Concurrency Typing" is effectively added to the java language in a some what informal way.

Adding a @ThreadSafe annotation to the previous example allows CheckThread to catch the bug at compile time.

import java.util.*;
import org.checkthread.annotations.ThreadSafe;

public class SomeClass {

    private final Map<String,String> map = new HashMap<String,String>();
  
    // Invoked by multiple threads
    @ThreadSafe
    public void doStuff() {
        map.put("foo","bar");  // ERROR: Caught by CheckThread
    }
}

Fixing Concurrency Bugs

The first step to fixing a concurrency bug is to determine the contract between the client code and the implementation. Is it thread safe, not thread safe, or thread confined? The best contract depends on the larger application architecture and requirements.

In the previous example, we can maintain the thread safe contract by synchronizing access to the HashMap. There are quite a few approaches: we can use Hashtable, Collections.synchronizedMap(...), or do synchronization in our own Java class.

import java.util.*;
import org.checkthread.annotations.ThreadSafe;

public class SomeClass {

    private final Map<String,String> map = new HashMap<String,String>();
  
    // Invoked by multiple threads
    @ThreadSafe
    public void doStuff() {
        synchronized(map) {
             map.put("foo","bar");  // OK: CheckThread reports no errors
        }
    }
}

Using XML to Express Thread Policies

Instead of adding annotations to our Java classes, we could alternatively add a threadpolicy.xml file to our root top level package on the class path. Whether to use XML or annotations depends on the application and requirements.

The following XML tells CheckThread that any methods defined on the com.mypackage.SomeClass class are ThreadSafe. Regular expressions can be used on XML attributes called "pattern".

<?xml version="1.0"?>
<!-- Sample Java Thread Policy Descriptor -->

<threadpolicy version="1.0">

    <class pattern="com.mypackage.SomeClass">
        <policy type="ThreadSafe">
             <!-- Use regular expressions to apply 
                  policy to all methods of the class -->
             <method pattern=".*" /> 
        </policy>
    </class> 

</threadpolicy>
©2009 CheckThread