Volatile is a lightweight synchronization mechanism provided by Java and can be understood as a synchronization lock for a variable. Whereas synchronized is mostly a method or block of code that locks, volatile locks only one variable, making it lighter. Of course, the JDK is getting better and better at synchronizing. It’s not as heavy as you’d expect, and you can safely use synchronized when you need to keep a method thread-safe.
The principle of
When the computer system is calculated, the CPU will read data from memory cache own register (CPU space is very small in a block of memory space, convenient calculation values, don’t need to read every time memory, most computers are multicore computers, there are multiple cpus, register here to other CPU is invisible, below
When a variable is declared as volatile, it is not cached in a CPU register. Each time it is directly operated on, other threads read the latest value each time.
features
- Variable visibility: Volatile variables are visible to all threads. If one thread changes the value of a variable, other threads immediately acquire the new value.
- Disallow instruction reordering: In JVM compilers and cpus, normal operation instructions are sometimes reordered to optimize efficiency, and volatile variables disallow instruction reordering.
For example,
One safe way to write the familiar singleton pattern is by double-checking it as follows
public class Single { private static volatile Single single = null; private Single() { } public static Single getInstance() { if (single == null) { synchronized (single) { if (single == null) { single = new Single(); } } } return single; }}Copy the code
The code declares the Single object as volatile. What happens if it is not volatile? If we look at single = new single (), the normal operation would look like this:
- Allocate memory address M;
- Initialize the Single object on memory M;
- Assign M’s address to single;
However, instructions are rearranged at compile time and the operation looks like this:
- Allocate memory address M;
- Assign M’s address to single;
- Initialize the Single object on memory M;
Back in the code, when thread A executes the second step in single = new single (), thread B enters the getInstance() method and checks if (single == null). Thread B will return a single object directly, but this thread will get an empty object. There is no initialized object in memory M.
Declaring the single variable as volatile avoids this kind of instruction reordering problem.
conclusion
When multiple threads operate on a shared variable, declare it as volatile to ensure that the shared variable is thread safe.