Characteristics of volatile
When we declare the shared variable to be volatile, the read/write to this variable will be very special. A good way to understand the volatile feature is to take a single read/write of the volatile variable as a synchronization of the individual read/write operations using the same monitor lock. Let's take a look at the sample code below, which is illustrated by a specific example:
Class Volatilefeaturesexample {
volatile long vl = 0L; Use volatile to declare a 64-bit long variable public
void set (long l) {
VL = l; The write of a single volatile variable is public
void Getandincrement () {
vl++; The read/write of a composite (multiple) volatile variable is public
long get () {return
VL; Read} for a single volatile variable
Suppose there are multiple threads that call three methods of the above program, which are semantically equivalent to the following program:
Class Volatilefeaturesexample {
long vl = 0L; 64-bit long normal variable public
synchronized void set (long l) { //write the same monitor synchronization for a single generic variable
VL = l;
}
public void Getandincrement () {//normal method call
Long temp = get (); Call synchronized Read Method
temp + 1L; General write operation
Set (temp); Invoke a synchronized write method
} public
synchronized long get () {
//to read a single generic variable synchronously with the same monitor return
VL;
}
As shown in the example above, a single read/write operation for a volatile variable is synchronized with a read/write operation with a normal variable, and the execution effect is the same for the same monitor lock.
The Happens-before rule of the monitor lock guarantees memory visibility between the release monitor and the two threads that get the monitor, which means that the read of a volatile variable always sees (any thread) the last write to the volatile variable.
The semantics of the monitor lock determines that the execution of the critical area code is atomic. This means that even a 64-bit long and double variable, as long as it is a volatile variable, reads and writes to that variable to be atomic. In the case of multiple volatile operations or similar volatile++, these operations are not atomic in their entirety.
In short, the volatile variable itself has the following characteristics:
Visibility. For a volatile variable to read, it is always possible to see (any thread) the last write to the volatile variable.
Atomicity: It is atomic to read/write to any single volatile variable, but similar to volatile++ this composite operation is not atomic.
The happens before relationship volatile writing-reading establishment
The above is about the characteristics of the volatile variable itself, for programmers, the impact of volatile on the memory visibility of the thread is more important than volatile's own characteristics, but also need our attention.
Starting with JSR-133, the write-read of volatile variables enables communication between threads.
From the memory semantics point of view, volatile has the same effect as the monitor lock: volatile write and monitor release have the same memory semantics; volatile read has the same memory semantics as the monitor's acquisition.
Consider the following example code using the volatile variable:
Class Volatileexample {
int a = 0;
Volatile Boolean flag = false;
public void writer () {
a = 1; 1
flag = true; 2
} public
void Reader () {
if (flag) { //3
int i = A; 4. ...
}}