Bartosz Popiela
Bartosz Popiela

Reputation: 1031

Java Memory Model guarantees for volatile

I have few doubts about volatile semantics.
Assume there are three threads T1, T2 and T3 and a single instance of the given class.

class Foo {
    private int x = 1;
    private int y = 2;
    private int z = 3;
    private volatile int w = 4;
    private volatile int v = 5;

    public void setX(int x) {
        this.x = x;
    }

    public int getX() {
        return this.x;
    }

    (...)
}

Let's say the following sequence of read/write actions occurs:

1. (T1) foo.getX(); // stored in a local memory of T1
2. (T1) foo.getY(); // stored in a local memory of T1

3. (T2) foo.setX(10);
4. (T2) foo.setY(20);

5. (T3) foo.getY(); // T3 may see 2 or 20, no guarantees if a write action from point 4 is visible to T3
6. (T3) foo.setZ(30);
7. (T3) foo.setW(40);
8. (T3) foo.setV(50);

9. (T1) foo.getW()
10. (T1) foo.getZ()
11. (T1) foo.getY()
12. (T1) foo.getX()

I know that it is guaranteed that T1 at point 9 will see a value set at point 7 and that T1 at point 10 will see a value set at point 6 (to be exact at least as up-to-date as this value).

But, are these statements true?

  1. Java Memory Model guarantees that T1 at point 11 will see a value at least as up-to-date as seen by T3 at point 5 (the one from a local memory of T3 or more actual, but even it there is a more actual value in the shared memory, it may not be visible to T1).
  2. There are no guarantees at all what T1 at point 12 sees, in particular no guarantees it sees a value set at point 3. Moreover, if there would be any write action to x before point 1 in any thread, T1 at point 12 could see some stale value. If there would be any value of x in a local memory of T3 in point 7, JMM guarantees it would be seen by T1 at point 12, but assuming there were no write/read actions on x in T3 prior to point 7, there are no such guarantees.
  3. There is no happens-before relation between point 8 and point 9, because these are different volatile variables. If JVM implements Java Memory Model in a way it flushes the local memory to the shared memory on a read action of a volatile variable and invalides the local memory on a write action to a volatile variable as states in the article for the synchronized semantics, then as a side effect there would a happens-before relation between point 8 and point 9, but it is not strictly defined in the Java Language Specification.
  4. If at point 7 and 8 there would be read actions instead write actions, T1 at point 10 would still see a value 30, because happens-before relation applies not only to write-read volatile sequence, but to read-read, write-write and read-write volatile sequences as well.

Please confirm that my understanding is correct.

Upvotes: 4

Views: 155

Answers (1)

Parthanon
Parthanon

Reputation: 388

As long as your get/set operations ONLY get and set the variable, then all of your assumptions will be correct.

In Java variables are stored in memory. But the compiler (and runtime) will allow a variable to be stored temporarily in the CPU cache to allow quicker read and writes for the duration of an algorithm or section of code.

The downside to this caching is that when the Core is done with the variable it will write it back to memory as if it was only updated once. The other cores can't see the state of the variable while it was being used. To make it worse, there is no order guarantee as to WHEN it will be written back to memory.

By setting a variable as Volatile you are telling java that the variable is not allowed to be put into ANY caches. A read or write on the variable must occur in memory.

This means that Volatile will make single operations on the variable atomic. But it will also make long operations on the variable a WHOLE LOT SLOWER. So volatile is not a solution for getting a performance increase out of multi-threaded code.

Notably, an operation that requires more than one read or write is not atomic. For example i++ which is actually i = i + 1 could have the value of i changed before the write is completed.

If you need to guarantee that operations occur atomically you can use a lock or semtex (slow) or you can use a clever paradigm like Copy-On-Write (COW) to allow atomic reads and atomic writes.

Upvotes: 1

Related Questions