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 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.
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:
RGBColor's constructor will always give the variables proper initial valuessetColor() and invert() will always perform valid state transformations on these variablesgetColor() 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.
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.
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.
JVMSimulator and Method.java and search for sychronized. http://www.artima.com/insidejvm/applets/sourcecode.html