Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Design for thread safety

Design tips on when and how to use synchronization, immutable objects, and thread-safe wrappers

  • Print
  • Feedback

Page 2 of 7

Given the architecture of the JVM, you need only be concerned with instance and class variables when you worry about thread safety. Because all threads share the same heap, and the heap is where all instance variables are stored, multiple threads can attempt to use the same object's instance variables concurrently. Likewise, because all threads share the same method area, and the method area is where all class variables are stored, multiple threads can attempt to use the same class variables concurrently. When you do choose to make a class thread-safe, your goal is to guarantee the integrity -- in a multithreaded environment -- of instance and class variables declared in that class.

You needn't worry about multithreaded access to local variables, method parameters, and return values, because these variables reside on the Java stack. In the JVM, each thread is awarded its own Java stack. No thread can see or use any local variables, return values, or parameters belonging to another thread.

Given the structure of the JVM, local variables, method parameters, and return values are inherently "thread-safe." But instance variables and class variables will only be thread-safe if you design your class appropriately.

RGBColor #1: Ready for a single thread

As an example of a class that is not thread-safe, consider the RGBColor class, shown below. Instances of this class represent a color stored in three private instance variables: r, g, and b. Given the class shown below, an RGBColor object would begin its life in a valid state and would experience only valid-state transitions, from the beginning of its life to the end -- but only in a single-threaded environment.

// In file threads/ex1/RGBColor.java
// Instances of this class are NOT thread-safe.
public class RGBColor {
    private int r;
    private int g;
    private int b;
    public RGBColor(int r, int g, int b) {
        checkRGBVals(r, g, b);
        this.r = r;
        this.g = g;
        this.b = b;
    }
    public void setColor(int r, int g, int b) {
        checkRGBVals(r, g, b);
        this.r = r;
        this.g = g;
        this.b = b;
    }
    /**
    * returns color in an array of three ints: R, G, and B
    */
    public int[] getColor() {
        int[] retVal = new int[3];
        retVal[0] = r;
        retVal[1] = g;
        retVal[2] = b;
        return retVal;
    }
    public void invert() {
        r = 255 - r;
        g = 255 - g;
        b = 255 - b;
    }
    private static void checkRGBVals(int r, int g, int b) {
        if (r < 0 || r > 255 || g < 0 || g > 255 ||
            b < 0 || b > 255) {
            throw new IllegalArgumentException();
        }
    }
}


Because the three instance variables, ints r, g, and b, are private, the only way other classes and objects can access or influence the values of these variables is via RGBColor's constructor and methods. The design of the constructor and methods guarantees that:

  1. RGBColor's constructor will always give the variables proper initial values

  2. Methods setColor() and invert() will always perform valid state transformations on these variables

  3. Method getColor() will always return a valid view of these variables


Note that if bad data is passed to the constructor or the setColor() method, they will complete abruptly with an InvalidArgumentException. The checkRGBVals() method, which throws this exception, in effect defines what it means for an RGBColor object to be valid: the values of all three variables, r, g, and b, must be between 0 and 255, inclusive. In addition, in order to be valid, the color represented by these variables must be the most recent color either passed to the constructor or setColor() method, or produced by the invert() method.

If, in a single-threaded environment, you invoke setColor() and pass in blue, the RGBColor object will be blue when setColor() returns. If you then invoke getColor() on the same object, you'll get blue. In a single-threaded society, instances of this RGBColor class are well-behaved.

Throwing a concurrent wrench into the works

Unfortunately, this happy picture of a well-behaved RGBColor object can turn scary when other threads enter the picture. In a multithreaded environment, instances of the RGBColor class defined above are susceptible to two kinds of bad behavior: write/write conflicts and read/write conflicts.

Write/write conflicts
Imagine you have two threads, one thread named "red" and another named "blue." Both threads are trying to set the color of the same RGBColor object: The red thread is trying to set the color to red; the blue thread is trying to set the color to blue.

Both of these threads are trying to write to the same object's instance variables concurrently. If the thread scheduler interleaves these two threads in just the right way, the two threads will inadvertently interfere with each other, yielding a write/write conflict. In the process, the two threads will corrupt the object's state.

The Unsynchronized RGBColor applet
The following applet, named Unsynchronized RGBColor, demonstrates one sequence of events that could result in a corrupt RGBColor object. The red thread is innocently trying to set the color to red while the blue thread is innocently trying to set the color to blue. In the end, the RGBColor object represents neither red nor blue but the unsettling color, magenta.

For some reason, your browser won't let you see this way cool Java applet.


To step through the sequence of events that lead to a corrupted RGBColor object, press the applet's Step button. Press Back to back up a step, and Reset to back up to the beginning. As you go, a line of text at the bottom of the applet will explain what's happening during each step.

For those of you who can't run the applet, here's a table that shows the sequence of events demonstrated by the applet:

Thread Statement r g b Color
none object represents green 0 255 0  
blue blue thread invokes setColor(0, 0, 255) 0 255 0  
blue checkRGBVals(0, 0, 255); 0 255 0  
blue this.r = 0; 0 255 0  
blue this.g = 0; 0 255 0  
blue blue gets preempted 0 0 0  
red red thread invokes setColor(255, 0, 0) 0 0 0  
red checkRGBVals(255, 0, 0); 0 0 0  
red this.r = 255; 0 0 0  
red this.g = 0; 255 0 0  
red this.b = 0; 255 0 0  
red red thread returns 255 0 0  
blue later, blue thread continues 255 0 0  
blue this.b = 255 255 0 0  
blue blue thread returns 255 0 255  
none object represents magenta 255 0 255  


As you can see from this applet and table, the RGBColor is corrupted because the thread scheduler interrupts the blue thread while the object is still in a temporarily invalid state. When the red thread comes in and paints the object red, the blue thread is only partially finished painting the object blue. When the blue thread returns to finish the job, it inadvertently corrupts the object.

  • Print
  • Feedback

Resources
  • The discussion forum devoted to the material presented in this article. http://www.artima.com/flexiblejava/fjf/threadsafety/index.html
  • Recommended books on Java design http://www.artima.com/designtechniques/booklist.html
  • Source packet that contains the example code used in this article http://www.artima.com/flexiblejava/code.html
  • Source code for the JVM Simulator applets, which, as mentioned in the article, include some thread-safe classes. Look at JVMSimulator and Method.java and search for sychronized. http://www.artima.com/insidejvm/applets/sourcecode.html
  • Object orientation FAQ http://www.cyberdyne-object-sys.com/oofaq/
  • 7237 Links on Object Orientation http://www.rhein-neckar.de/~cetus/software.html
  • The Object-Oriented Page http://www.well.com/user/ritchie/oo.html
  • Collection of information on OO approach http://arkhp1.kek.jp:80/managers/computing/activities/OO_CollectInfor/OO_CollectInfo.html
  • Design Patterns Home Page http://hillside.net/patterns/patterns.html
  • A Comparison of OOA and OOD Methods http://www.iconcomp.com/papers/comp/comp_1.html
  • Object-Oriented Analysis and Design MethodsA Comparative Review http://wwwis.cs.utwente.nl:8080/dmrg/OODOC/oodoc/oo.html
  • Patterns discussion FAQ http://gee.cs.oswego.edu/dl/pd-FAQ/pd-FAQ.html
  • Implementing Basic Design Patterns in Java (Doug Lea) http://www.oswego.edu/dl/pats/ifc.html
  • Patterns in Java AWT http://mordor.cs.hut.fi/tik-76.278/group6/awtpat.html
  • Software Technology's Design Patterns Page http://www.sw-technologies.com/dpattern/
  • Previous Design Techniques articles http://www.javaworld.com/topicalindex/jw-ti-techniques.html