Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to comprehend "The variable does not participate in invariants with other state variables when using volatile keyword"?

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 

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

How to comprehend "The variable does not participate in invariants with other state variables when using volatile keyword"?

like image 202
xing.zhang Avatar asked Mar 26 '12 08:03

xing.zhang


1 Answers

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:

  • The variable isn't involved in invariants related to other variables (for the reason explained above).
  • The value to write on the variable does not depend on its current value.

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.

like image 80
Adriano Repetti Avatar answered Nov 16 '22 04:11

Adriano Repetti