//Consider a simple class called Counter
class Counter {
private int c = 0;
public void increment() {
c++;
}
public void decrement() {
c--;
}
public int value() {
return c;
}
}
Counter
is designed so that each invocation of increment
will add 1 to c
, and each invocation of decrement
will subtract 1 from c
. However, if a Counter
object is referenced from multiple threads, interference between threads may prevent this from happening as expected. Interference happens when two operations, running in different threads, but acting on the same data, interleave. This means that the two operations consist of multiple steps, and the sequences of steps overlap.
It might not seem possible for operations on instances of Counter
to interleave, since both operations on c
are single, simple statements. However, even simple statements can translate to multiple steps by the virtual machine. We won't examine the specific steps the virtual machine takes — it is enough to know that the single expression c++
can be decomposed into three steps:
- Retrieve the current value of
c
. - Increment the retrieved value by 1.
- Store the incremented value back in
c
.
c--
can be decomposed the same way, except that the second step decrements instead of increments. Suppose Thread A invokes increment
at about the same time Thread B invokes decrement
. If the initial value of c
is 0
, their interleaved actions might follow this sequence:
- Thread A: Retrieve c.
- Thread B: Retrieve c.
- Thread A: Increment retrieved value; result is 1.
- Thread B: Decrement retrieved value; result is -1.
- Thread A: Store result in c; c is now 1.
- Thread B: Store result in c; c is now -1.
//synchronized
public class SynchronizedCounter {
private int c = 0;
public synchronized void increment() {
c++;
}
public synchronized void decrement() {
c--;
}
public synchronized int value() {
return c;
}
}
If
count
is an instance of SynchronizedCounter
, then making these methods synchronized has two effects: - First, it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
- Second, when a synchronized method exits, it automatically establishes a happens-before relationship with any subsequent invocation of a synchronized method for the same object. This guarantees that changes to the state of the object are visible to all threads.
Note that constructors cannot be synchronized — using the synchronized
keyword with a constructor is a syntax error. Synchronizing constructors doesn't make sense, because only the thread that creates an object should have access to it while it is being constructed.
沒有留言:
張貼留言