|
|
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 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.