Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
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
Page 3 of 5
After threading, the second problem with the naive implementation is that there's no way to guarantee that all the existing
objects stay in synch with changes to the class variables. A sloppy programmer can add an instance method (one that is not
static) to the Window class, and that instance method can change the foreground or background fields without notifying the other windows, or even without updating its own color.
You can fix both the race-condition and lack-of-update problems by encapsulating the two static fields in a class of their own:
class Color_scheme { private Color foreground = SystemColor.windowText; private Color background = SystemColor.window; /*package*/ synchronized 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. } } class Window // not the AWT window { static Scheme color_scheme = new Color_scheme(); static change_color_scheme( Color foreground, Color background ) { scheme.change_color_scheme( foreground, background ); } }
Now there's no way to modify the foreground or background color without notifying the other windows. Note that this is one
of the few cases in which you must use package access rather than an inner class. Had Color_scheme been an inner class of Window, direct access to foreground and background would still be possible from methods of Window. This approach also has the advantage of making the monitor that controls the Color_scheme more visible -- it's obviously the one associated with the explicit Color_scheme object, not the one associated with the Window.
There's another problem with the earlier code, however. We really want only one Color_scheme to exist, ever. In the earlier code, I've done it accidentally by making the reference static and only calling new once, but I'd really like to guarantee that only one instance of the object can exist. The Gang of Four's (see Resources) Singleton pattern describes exactly this situation. Two excerpts from the Gang of Four book are relevant. The "Intent" section
in the Gang of Four book's chapter on singletons states:
Ensure a class only has one instance, and provide a global point of access to it.
and the "Consequences" section says:
[Singleton] permits a variable number of instances. The pattern makes it easy to change your mind and allow more than one instance of the singleton class. Moreover, you can use the same approach to control the number of instances that the application uses. Only the [Instance] operation that grants access ot the singleton instance needs to change.
That excerpt from the "Consequences" section is interesting because it allows a Class object to be considered a singleton, even though there's more than one instance of the Class class in the program. It's guaranteed that there will be only a single instance of Class for a given class, so it's a singleton: Some_class.class (the "operation that grants access") always evaluates to the same Class object. The static fields and methods, since they are members of the Class object, define the state and methods of the singleton object as well. Exploiting this reasoning, I can ensure that only one
instance of the Color_scheme exists by moving everything into the Class object (making everything static):
class Color_scheme { private static Color foreground = SystemColor.windowText; private static Color background = SystemColor.window; private Color_scheme(){} /*package*/ synchronized static 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. } }
Note that I've also added a private constructor. A class, all of whose constructors are private, can be created only by a new that's invoked in a method that legitimately has access to the class's other private components. There are no such methods here, so no instances of Color_scheme can actually be created. This guarantees that only one object can exist -- the Class object, a singleton.
I also have to change the Window to use the Class object rather than a specific instance:
class Window // not the AWT window { // Note that there's no field here, now. change_color_scheme( Color foreground, Color background ) { Color_scheme.change_color_scheme( foreground, background ); } }
I've eliminated the static field in the Window class and have invoked change_color_scheme() directly through the class.
This sort of singleton -- a class all of whose methods are static -- is called a Booch utility (after Grady Booch, who identified the pattern in one of his early books). Java's Math class is a good example of a utility-style singleton.
The problem with the make-everything-static approach to singleton creation is that all the information needed to create the object must be known at class-load time,
and that isn't always possible. Java's Toolkit is a good example. An application must load a different Toolkit than an applet, but a given chunk of code doesn't know whether it's running in an application or an applet until runtime.
The actual instance of the toolkit is brought into existence by calling the static method Toolkit.getDefaultToolkit(). The object itself doesn't exist until the method is called the first time. Subsequent calls return a reference to the object
that's created by the first call.
Critical sections
Bringing a singleton into existence at runtime (rather than at load-time) is fraught with peril in a multithreaded environment.
You can implement the creation function naively as follows:
public static synchronized Singleton get_instance() { if( instance == null ) instance = new Singleton(); return instance; }
The static synchronized method forms a critical section -- a block of code that can be executed by only one thread at a time. If get_instance() weren't synchronized, a thread could be preempted after the if statement was processed, but before the instance=new Singleton() was executed. The preempting thread could then call get_instance(), create an instance, and yield. The preempted thread would then wake up, think that there were no instances (because it has
already performed the test), and create a second instance of the object. The "critical section" eliminates the multiple-creation
problem by preventing any thread from entering get_instance() if any other thread is already inside the method. Any singleton object can be used to implement a critical section. Here,
the Class object whose monitor we're using is itself a singleton, so by locking this object implicitly when we enter the static method, we prevent other threads from executing the method in parallel. (All synchronized static methods actually are critical sections when you look at them that way.)