How to understand "a variable is not involved in invariants with other state variables when using volatile keyword"?

From the book “Java Concurrency in Practice” p. 26:

You can use mutable variables only when all of the following criteria are met:

  • Writes to a variable independent of its current value, or you can guarantee that only one thread never updates the value;

  • The variabledoes is not involved in invariants with other variable states; and

  • Locking is not required for any other reason, while the variable is being accessed.

How to understand "a variable is not involved in invariants with other state variables when using the volatile keyword"?

+7
source share
1 answer

A simple definition of "invariant": a condition that is always true during the life of an object.

Volatile variables do not share the atomicity features of synchronized blocks.

This is why you cannot use them in a class that has invariants that bind several variables.

For example, imagine that you have a class to simulate a time interval described by two variables: start and end . The condition of the invariant may be that start always less than or equal to end . If both variables (as an example) are declared volatile, then you can rely on the volatile visibility functions, but you cannot be sure that during a change that includes both variables, the invariant is always executed. 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 for each thread, but in the middle of two instructions the state of the object may be invalid. Since it can be accessed by other threads (remember that this is a simple case, so it is possible, but unlikely), then the condition of the start <end invariant may be violated.

Therefore, the use of volatility is somehow discouraged outside the (small) set of well-defined patterns. A mutable variable should only be used if these conditions are met:

  • The variable is not involved in the invariants associated with other variables (for the reason described above).
  • The value for writing to the variable does not depend on its current value.

For example, the expression int a = i++; is not atomic, then it is not, strictly speaking, thread safe, because it will be rewritten something like this:

 int temp = i; i = i + 1; int a = temp; 

To make it atomic in terms of flow, you can imagine a class like this:

 public class MyAtomicInteger { public synchronized increment() { x = x + 1; } private int x; } 

Of course, there is a real implementation of this AtomicInteger , and it is part of the java.util.concurrent.atomic package, it provides some simple basic procedures for parallel programming without blocking.

+15
source

All Articles