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

Programming Java threads in the real world, Part 7

Singletons, critical sections, and reader/writer locks

  • Print
  • Feedback

Page 2 of 5

To best explain how the two types of variables are used in practice, an example seems in order. Back in the dark ages (the early 1990s) somebody had the bright idea that every window on a computer screen should use a different color scheme, even within a single application. Magenta backgrounds with yellow borders, turquoise backgrounds with chartreuse borders -- it make your eyes hurt. (The reasoning was that the users would somehow remember the color combinations and more easily identify the windows. Nice theory, but the human mind just doesn't work that way.) In this system, a window's color scheme is an "instance variable": every instance -- every window -- potentially has a different value for its color scheme.

Eventually, people came to their senses and made all the windows the same color. Now the color scheme is a "class variable." The entire class of window objects uses the same color scheme. If the scheme changes, then all the windows should change their appearance.

You can model the class-level behavior like this:

class Window                    // not the AWT window
{   
   private static Color foreground = SystemColor.windowText;
   private static Color background = SystemColor.window;
synchronized static public change_color_scheme( Color foreground, Color background )
    {
        this.foreground = foreground;
        this.background = background;
        // code goes here that tells all the extant Window objects to
        // redraw themselves with the new color scheme.
    }
}


There are several problems with this simplistic approach, however, the first being threading.

Java creates a Class class object for every class in your system, and the static fields are members of this Class object. A Class object is a real object: It has methods (declared static in the class definition) and state (defined by the static fields). The Class object also has its own monitor. When you call a synchronized static method, you enter the monitor associated with the Class object. This means that no two synchronized static methods can access the static fields of the class at the same time. You can also lock the Class object explicitly, like this:

synchronized( Window.class )
{   // modify static fields here
}


Unfortunately, the Class-level monitor is in no way connected to the monitors of the various instances of the object, and a synchronized, but nonstatic, method can also access the static fields. Entering the synchronized nonstatic method does not lock the Class object. Why is this a problem? Well, in the previous example, it would appear to be harmless to omit the static (but not the synchronized) from the definition of change_color_scheme() since the static fields will be modified, even if the modifying method isn't static. Appearances are deceiving, though. If two threads simultaneously send change_color_scheme() messages to two different objects of class Window, a race condition results, and the color scheme will be in an unknown state. In other words, the individual Window objects are locked, but locking a Window object does not lock the corresponding Class object (which contains the class variables), and the static fields are unguarded. Consequently, we have two threads modifying two variables at the same time.

  • Print
  • Feedback

Resources
  • Bill Venners discussed static members, though without much coverage of the implementation issues, in his Design Techniques column, "Design with static members" http://www.javaworld.com/javaworld/jw-03-1999/jw-03-techniques.html
  • The Singleton pattern is presented in the "Gang of Four" (or GoF) bookErich Gamma, Richard Helm, Ralph Johnson, and John Vlissides's Design Patterns Elements of Reusable Object-Oriented Software (Reading, MAAddison Wesley, 1995). This book is essential reading for any OO designer.
  • John Vlissides's Pattern HatchingDesign Patterns Applied (Reading, MAAddison Wesley, 1998) also has a lot to say about singletons in Chapter 2 and the first section of Chapter 3.
  • The double-checked locking strategy for singleton creation is described in "Double-Checked Locking" by Douglas C. Schmidt and Tim Harrison, Pattern Languages of Program Design 3 (Reading, MAAddison Wesley, 1998, pp. 363-375).
  • Reader/writer locks are described in Doug Lea's Concurrent Programming in Java (Reading, MAAddison Wesley, 1997, pp. 300-303). My implementation is based on Lea's.
  • Reader/writer locks are also described in Scott Oaks and Henry Wong's Java Threads (Sebastopol, CAO'Reilly, 1997, pp. 180-187).