CheckThread.org (Beta)

Example: Simple Race Condition

In the following example, is it possible for the barf() method to ever run?

public class SomeClass {

    private volatile boolean flag = 0;
  
    // Invoked by multiple threads
    public void doStuff() {

        flag = true;
        if(flag!=true) {
            barf(); // Massive failure
        }
        flag = false;
    }
}

Yes - if multiple threads are calling this method concurrently, it's possible for one thread to invoke "flag=false" before another thread calls "if flag!=true". Inspection of the code, however, makes this race condition not obvious. It would appear like the "if" statement condition would never be true.

Using a volatile modifier doesn't prevent the race condition as the volatile keyword only ensures the variable is read from main memory. A better way to see this is to inspect the equivalent bytecode for the "doStuff" method -depicted below:

Equivalent Byte Code for Method "doStuff"
0 aload_0
1 iconst_1
2 putfield var    // write shared data field
5 aload_0
6 getfield var    // read shared data field        
9 ifne
...
18 putfield var   // write shared data field       
21 return

Multiple threads can potentionally interleave unsynchronized operations with one another leading to race conditions.

Race conditions are sometimes acceptable and don't necessarily imply a bug, but it's always important for the Java developer to be aware of the undeterministic behavior. To learn more about race conditions and concurrency, see the Literature References section.

Example: Catching Race Conditions at Compile Time

With CheckThread, the race condition can be caught at compile time before even running the code. By declaring the method "ThreadSafe" with an annotation or using threadpolicy.xml, CheckThread will inspect the byte code to ensure that no shared data fields are undergoing two separate read and write operations without synchronization.

import org.checkthread.annotations.ThreadSafe;
	
public class SomeClass {

    private volatile boolean flag = 0;
  
    // Invoked by multiple threads
    @ThreadSafe
    public void doStuff() {

        flag = true;
        if(flag!=true) {
            barf(); // ERROR: Caught by CheckThread
        }
        flag = false;
    }
}

Example: Preventing Race Conditions

There are quite a few different techniques a Java developer can implore to fix the race condition in the previous example. A simple technique is to synchronize access to share data so that only one thread accesses runs the method at any time.

import org.checkthread.annotations.*;

public class SomeClass {

    private volatile boolean flag = 0;
    private final Object guard = new Object();
  
    // Invoked by multiple threads
    @ThreadSafe
    public void doStuff() {

        synchronized(guard) {
            flag = true;
            if(flag!=true) {
                barf(); // OK: CheckThread reports no errors
            }
            flag = false;
        }
    }
}

A caveat is that synchronization should be used judiciously. Sprinkling synchronization throughout Java code can lead to other types of problems like deadlocks and slow performance.

Other possible ways to fix the race condition include using a synchronized block inside the method, using the Java 1.5 java.util.concurrent.lock package, or using the Java 1.5 java.util.concurrent.atomic package.

©2009 CheckThread