From book "Java Concurrency in Practice" page 26:
You can use volatile variables only when all the following criteria are met:
Writes to the variable do not depend on its current value, or you can ensure that only a single thread ever updates the value;
The variabledoes not participate in invariants with other state variables; and
How to comprehend "The variable does not participate in invariants with other state variables when using volatile keyword"?
A simple definition of "invariant": a condition that is always true during the lifetime of an object.
Volatile variables do not share the atomicity features of
synchronized
blocks.
That's why you can't use them within a class that has invariants that relate multiple variables.
For example imagine you have a class
to model a time interval described by two variables: start
and end
. An invariant condition may be that start
is always less or equal than end
. If both variables (just as example) are declared as volatile then you can rely on visibility features of volatile
but you can't be sure that during a change that involves both variables the invariant is always satisfied. Think:
public void setInterval(Date newStart, Date newEnd)
{
// Check if inputs are correct
// Here the object state is valid
start = newStart;
// If another thread accesses this object now it will
// see an invalid state because start could be greater than end
end = newEnd;
// Here the object state is valid again
}
In this case you can be sure that the change is visible to every thread but in the middle of the two instructions the object state could be not valid. Because it can be accessed by other threads (remember this is a simple case so it's possible but not likely) then the invariant condition "start < end" could be broken.
That's why the use of volatile is somehow discouraged outside a (small) set of well defined patterns. A volatile variable should be used only if these conditions are satisfied:
For example the expression int a = i++;
isn't atomic then it's not - strictly speaking - thread-safe because it'll be rewritten with something like this:
int temp = i;
i = i + 1;
int a = temp;
To make it atomic from a thread point of view you can imagine a class like this:
public class MyAtomicInteger
{
public synchronized increment()
{
x = x + 1;
}
private int x;
}
Of course it exists a true implementation of this AtomicInteger
and it's part of the package java.util.concurrent.atomic, it provides some simple basic routines for lock-free concurrent programming.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With