Mateusz Zakrzewski Mateusz Zakrzewski - 13 days ago 6
Java Question

How to write a simple thread-safe class using a volatile variable?

I want to write a simple thread-safe class that could be used to set or get an Integer value.

The easiest way is to use the synchronized keyword:

public class MyIntegerHolder {

private Integer value;

synchronized public Integer getValue() {
return value;
}

synchronized public void setValue(Integer value) {
this.value = value;
}

}


I could also try using volatile:

public class MyIntegerHolder {

private volatile Integer value;

public Integer getValue() {
return value;
}

public void setValue(Integer value) {
this.value = value;
}

}


Is the class with the volatile keyword thread-safe?

Consider the following sequence of events:


  1. Thread A sets the value to 5.

  2. Thread B sets the value to 7.

  3. Thread C reads the value.



It follows from the Java Language Specification that


  • "1" happens-before "3"

  • "2" happens-before "3"



but I don't see how it could follow from the specification that "1" happens-before "2" so I suspect that "1" doesn't happen-before "2".

I suspect the thread C may read 7 or 5. I think the class with the volatile keyword is not thread-safe and the following sequence is also possible:


  1. Thread A sets the value to 5.

  2. Thread B sets the value to 7.

  3. Thread C reads 7.

  4. Thread D reads 5.

  5. Thread C reads 7.

  6. Thread D reads 5.

  7. ...



Am I correct in assuming that MyIntegerHolder with volatile is not thread-safe?

Is it possible to make a thread-safe Integer holder by using AtomicInteger:

public class MyIntegerHolder {

private AtomicInteger atomicInteger = new AtomicInteger();

public Integer getValue() {
return atomicInteger.get();
}

public void setValue(Integer value) {
atomicInteger.set(value);
}

}


?

Here is a fragment of the Java Concurrency In Practice book:


"Reads and writes of atomic variables have the same memory semantics
as volatile variables.
"


What is the best (preferably non-blocking) way of writing a thread-safe MyIntegerHolder?

If you know the answer, I would like to know why you think it is correct. Does it follow from the specification? If so, how?

Answer

The question was not easy for me, because I thought (incorrectly) that knowing everything about the happens-before relation gives one a complete understanding of the Java Memory Model - and the semantics of volatile.

I found the best explanation in this document: "JSR-133: JavaTM Memory Model and Thread Specification"

The most relevant fragment of the above document is the section "7.3 Well-Formed Executions".

The Java Memory Model guarantees that all executions of a program are well-formed. An execution is well-formed only if it

  • Obeys happens-before consistency
  • Obeys synchronization-order consistency
  • ... (some other conditions must also be true)

Happens-before consistency is usually enough to come to a conclusion about the program behavior - but not in this case, because a volatile write doesn't happen-before another volatile write.

The MyIntegerHolder with volatile is thread-safe, but it's safety comes from the synchronization-order consistency.

In my opinion when Thread B is about to set the value to 7, A doesn't inform B of everything it has done until that moment (as one of the other answers suggested) - it only informs B about the value of the volatile variable. Thread A would inform B about everything (assigning values to other variables) if the action taken by Thread B was read and not write (in that case, there would exist the happens-before relationship between the actions taken by these two threads).

Comments