Declaring shared variables as volatile ensures visibility and limits reordering of accesses. Volatile accesses do not guarantee the atomicity of composite operations such as incrementing a variable (CON01-J. Do not assume that composite operations on primitive data are atomic).
Declaring variables as volatile establishes a happens-before relationship such that a write to the volatile variable is always seen by a subsequent read. Statements that occur before the write to the volatile field also happen-before the read of the volatile field.
Consider two threads that are executing some statements:
...
Thread 1 and Thread 2 have a happens-before relationship such that Thread 2 does not start before Thread 1 finishes. This is established by the semantics of volatile accesses.
In this example, Statement 3 writes to a volatile variable, and statement 4 in the second thread, (in Thread 2) reads the same volatile variable. The read sees the most recent write (to the same variable v
) from statement 3.
Volatile read and write operations cannot be reordered with respect to each other and also with respect to nonvolatile variables accesses. When Thread 2 reads the volatile variable it sees the results of all the writes occurring before the write to the volatile variable in Thread 1. Because of the relatively strong guarantees of volatile, the performance overhead of volatile is almost the same as that of synchronization
However, this does not mean that statements 1 and 2 are executed in the order in which they appear in the program. They may be freely reordered by the compiler. In fact, if statement 1 constituted a read of some variable x
, it could see the value of a future write to x
in statement 2. These stronger volatile semantics, however, increases the cost of volatile almost to cost of synchronization.
Wiki Markup |
---|
The possible reorderings between {{volatile}} and nonvolatilenon-volatile variables are summarized in the matrix shown below. The loadLoad and store operations correspondare synonymous to read and write operations that use the variable, respectively. \[[Lea 08|AA. Java References#Lea 08]\] |
...
Code Block | ||
---|---|---|
| ||
final class ControlledStop implements Runnable { private volatile boolean done = false; public void run() { while (!done) { try { // ... Thread.currentThread().sleep(1000); // Do something } catch(InterruptedException ie) { // handle exception } } } protected void shutdown(){ done = true; } } |
Noncompliant Code Example (nonvolatile guard)
This noncompliant code example declares a nonvolatile non-volatile variable of type int
which is initialized in the constructor depending on a security check.
Code Block | ||
---|---|---|
| ||
class BankOperation { private int balance = 0; private boolean initialized = false; public BankOperation() { if (!performAccountVerification()) { throw new SecurityException("Invalid Account"); } balance = 1000; initialized = true; } private int getBalance() { if (initialized == true) { return balance; } else { return -1; } } } |
In a multi-threading scenario, it is possible that the statements will be reordered The Java compiler is allowed to reorder the statements of the BankOperation()
constructor so that the boolean
flag initialized
is set to true
before the initialization has concluded. If it is possible to obtain a partially initialized instance of the class in a subclass using a finalizer attack (see OBJ04-J. Do not allow partially initialized objects to be accessed), a race condition can be exploited by invoking the getBalance()
method to obtain the balance even though initialization is still underway.
Compliant Solution (volatile guard)
This compliant solution declares the initialized
flag as volatile to ensure that the initialization statements are not reorderedinitialization happens before the initialized
flag is set.
Code Block | ||
---|---|---|
| ||
class BankOperation { private int balance = 0; private volatile boolean initialized = false; // DeclaredNow volatile public BankOperation() { if (!performAccountVerification()) { throw new SecurityException("Invalid Account"); } balance = 1000; initialized = // ... } |
...
true;
}
private int getBalance() {
if (initialized == true) {
return balance;
}
else {
return -1;
}
}
}
|
Noncompliant Code Example (visibility)
This noncompliant code example consists of two classes, : an immutable ImmutablePoint
class and a mutable Holder
class.
...