Question

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?

Was it helpful?

Solution 5

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).

OTHER TIPS

The keyword synchronized is saying that if Thread A and Thread B want to access the Integer, they cannot do so simultaneously. A is telling B wait until I'm done with it.

On the other hand, volatile makes threads more "friendly". They start talking to each other and working together to perform tasks. So when B tries to access, A will inform B of everything it has done until that moment. B is now aware of the changes and can continue its job from where A left of.

In Java, you have Atomic for this reason, which under the covers use the volatile keyword, so they are doing pretty much the same thing, but they save you time and effort.

The thing you are looking for is AtomicInteger, you are right about this. For the operation you are trying to perform this is the best choice.

There are two main uses of `AtomicInteger`:

 * As an atomic counter (incrementAndGet(), etc) that can be used by many threads concurrently

 * As a primitive that supports compare-and-swap instruction (compareAndSet()) to implement non-blocking algorithms. 

To answer your question on a general note

It depends on what you need. I'm not saying synchronized is wrong and volatile is good, otherwise the nice Java people would have removed synchronized a long time ago. There is no absolute answer, there are a lot of specific cases and usage scenarios.

A few of my bookmarks:

Concurrency tips

Core Java Concurrency

Java concurrency

Update

From the Java Concurrency specification available here:

Package java.util.concurrent.atomic

A small toolkit of classes that support lock-free thread-safe programming on single variables.

Instances of classes `AtomicBoolean`, `AtomicInteger`, `AtomicLong`, and `AtomicReference` each provide access and updates to a single variable of the corresponding type.
Each class also provides appropriate utility methods for that type.
For example, classes `AtomicLong` and AtomicInteger provide atomic increment methods.

The memory effects for accesses and updates of atomics generally follow the rules for volatiles:

get has the memory effects of reading a volatile variable.
set has the memory effects of writing (assigning) a volatile variable.

Also from Here

The Java programming language volatile keyword:

(In all versions of Java) There is a global ordering on the reads and writes to a volatile variable. This implies that every thread accessing a volatile field will read its current value before continuing, instead of (potentially) using a cached value. (However, there is no guarantee about the relative ordering of volatile reads and writes with regular reads and writes, meaning that it's generally not a useful threading construct.)

If you need only get / set on a variable it is enough to declare it volatile like you did. If you check how AtomicInteger set / get work you will see the same implementation

private volatile int value;
...

public final int get() {
    return value;
}

public final void set(int newValue) {
    value = newValue;
}

but you cannot increment a volatile field atomically this simple. This is where we use AtomicInteger.incrementAndGet or getAndIncrement methods .

Chapter 17 of the Java Language Specification defines the happens-before relation on memory operations such as reads and writes of shared variables. The results of a write by one thread are guaranteed to be visible to a read by another thread only if the write operation happens-before the read operation.

  1. The synchronized and volatile constructs, as well as the Thread.start() and Thread.join() methods, can form happens-before relationships. In particular: Each action in a thread happens-before every action in that thread that comes later in the program's order.
  2. An unlock (synchronized block or method exit) of a monitor happens-before every subsequent lock (synchronized block or method entry) of that same monitor. And because the happens-before relation is transitive, all actions of a thread prior to unlocking happen-before all actions subsequent to any thread locking that monitor.
  3. A write to a volatile field happens-before every subsequent read of that same field. Writes and reads of volatile fields have similar memory consistency effects as entering and exiting monitors, but do not entail mutual exclusion locking.
  4. A call to start on a thread happens-before any action in the started thread.
  5. All actions in a thread happen-before any other thread successfully returns from a join on that thread.

reference: http://developer.android.com/reference/java/util/concurrent/package-summary.html

from my understanding 3 means: if you write (not based read result) / read is fine. if you write (based on read result, e.g., increment) / read is not fine. Since volatile "do not entail mutual exclusion locking"

Your MyIntegerHolder with volatile is thread safe. But AtomicInteger is preferred if you are doing concurrent program, because it also provides a lot of atomic operations.

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

You are right here that "1" happens-before "3" and "2" happens-before "3". "1" does not happens-before "2", but it doesn't mean that it is not Thread-safe. The thing is that the example you provided is ambiguous. If you are saying "sets the value to 5", "sets the value to 7", "reads the value" happens sequentially, you can always read the value of 7. And it is nonsense to put them in different threads. But if you are saying that 3 threads executes concurrently without sequence, you can even get value of 0, because "reads the value" could happen first. But this is nothing with Thread-safe, there is no order expecting from the 3 actions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top