Java Reference
In-Depth Information
Race Conditions and Thread Synchronization
When multiple threads change a shared variable, it is sometimes possible that the
variable will end up with the wrong (and often unpredictable) value. This is called a
race condition because the final value depends on the sequence in which the threads
access the shared value.
For example, consider two threads where each thread runs the following code:
race condition
int local;
local = sharedVariable;
local++;
sharedVariable = local;
The intent is for each thread to increment sharedVariable by one so if there are
two threads, then sharedVariable should be incremented by two. However, consider
the case where sharedVariable is 0. The first thread runs and executes the first two
statements, so its variable local is set to 0. Now there is a context switch to the second
thread. The second thread executes all four statements, so its variable local is set to 0
and incremented, and sharedVariable is set to 1. Now we return to the first thread
and it continues where it left off, which is the third statement. The variable local is 0
so it is incremented to 1 and then the value 1 is copied into sharedVariable . The end
result after both threads are done is that sharedVariable has the value 1, and we lost
the value written by thread two!
You might think that this problem could be avoided by replacing our code with a
single statement such as
sharedVariable++;
Unfortunately, this will not solve our problem because the statement is not
guaranteed to be an “atomic” action and there could still be a context switch to another
thread “in the middle” of executing the statement.
To demonstrate this problem, consider the Counter class shown in Display 19.4 .
This simple class merely stores a variable that increments a counter. It uses the
somewhat roundabout way to increment the counter on purpose to increase the
likelihood of a race condition.
The way we will demonstrate the race condition is to do the following:
1. Create a single instance of the Counter class.
2. Create an array of many threads (30,000 in the example) where each thread
references the single instance of the Counter class.
3. Each thread runs and invokes the increment() method.
4. Wait for each thread to fi nish and then output the value of the counter. If
there are no race conditions, then its value should be 30,000. If there are race
conditions, then the value will be less than 30,000.
We create many threads to increase the likelihood that the race condition occurs.
With only a few threads, it is not likely that there will be a switch to another thread
inside the increment() method at the right point to cause a problem.
 
Search WWH ::




Custom Search