A simple answer is as follows:
synchronized
can always be used to give you a thread-safe / correct solution,
volatile
will probably be faster, but can only be used to give you a thread-safe / correct in limited situations.
If in doubt, use synchronized
. Correctness is more important than performance.
Characterizing the situations under which volatile
can be used safely involves determining whether each update operation can be performed as a single atomic update to a single volatile variable. If the operation involves accessing other (non-final) state or updating more than one shared variable, it cannot be done safely with just volatile. You also need to remember that:
- updates to non-volatile
long
or a double
may not be atomic, and
- Java operators like
++
and +=
are not atomic.
Terminology: an operation is "atomic" if the operation either happens entirely, or it does not happen at all. The term "indivisible" is a synonym.
When we talk about atomicity, we usually mean atomicity from the perspective of an outside observer; e.g. a different thread to the one that is performing the operation. For instance, ++
is not atomic from the perspective of another thread, because that thread may be able to observe state of the field being incremented in the middle of the operation. Indeed, if the field is a long
or a double
, it may even be possible to observe a state that is neither the initial state or the final state!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…