2

Lets say I have the following class:

private final int[] ints = new int[5];

public void set(int index, int value) {
    ints[index] = value;
}

public int get(int index) {
    return ints[index]
}

Thread A runs the following:

set(1, 100);

(very) shortly after Thread B runs the following:

get(1)

My understanding is that there is no guarantee that Thread B will see the change that Thread A has been as the change could still be sitting in a CPU cache/register...or there could be instruction reordering...is this correct?

Moving further on, what happens if I have the following class:

public class ImmutableArray {

    public final int[] ints

    public ImmutableArray(int[] ints) {
        this.ints = ints
    }
}

With the following local variable:

volatile ImmutableArray arr;

and Thread A runs the following:

int[] ints = new int[5];
int[0] = 1;

arr = new ImmutableArray(ints);

(very) shortly after Thread B runs the following:

int i = arr.ints[0];

is Thread B guaranteed to get the value 1 because of the final and happens-before relationship, even despite the fact the value in the array was set outside of this?

EDIT: In the second example, the array is never changes, hence the name "ImmutableArray"

Second EDIT::

So what I understand by the answer is that given this:

int a = 0
volatile int b = 0;

If Thread A does the following:

a = 1;
b = 1;

Then the Thread B did the following:

a == 1; // true
b == 1; // true

So volatile acts as a sort of barrier, but at what point does the barrier end and allow reordering of instructions again?

Cheetah
  • 13,785
  • 31
  • 106
  • 190
  • 2
    Yes. No. [Blog](http://jeremymanson.blogspot.co.uk/2009/06/volatile-arrays-in-java.html) and [duplicate](http://stackoverflow.com/questions/15739942/java-alternatives-for-volatile-array) – Ordous Feb 11 '15 at 15:09
  • @Ordous Your comment is incorrect on second count. – Marko Topolnik Feb 11 '15 at 17:48

1 Answers1

2

You are correct on both counts. In fact, you would be right even if you relaxed your problem statement.

In the first example, no matter how much later thread B evaluates get(1), there will be no guarantee that it will ever observe the value written by thread A's call to set(1, 100).

In the second example, either final on the ints or volatile on the arr would be enough on its own for you to have the guarantee of observing ints[0] = 5. Without volatile you wouldn't be guaranteed to ever observe the ImmutableArray instance itself, but whenever you would observe it, you would be guaranteed to observe it in the fully constructed state. More specifically, the guarantee pertains to the complete state reachable from the object's final field as of the moment when the constructor returns.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Ah right, so the assigning the array reference to the volatile variable ensures that the contents of the array are written to memory?...is that the same with other data structures like a linked list for instance? – Cheetah Feb 11 '15 at 19:04
  • Try to avoid thinking in physical terms such as "ensures writing to memory" because ultimately they will mislead you. Keep to the guarantees provided by the *happens before* relationship as specified in fine detail by the Java Memory Model. Applied specifically to your comment above, *happens before* makes no distinction between arrays, linked lists, or even just a bunch of nonrelated objects. Whatever a thread wrote before assigning to a `volatile` variable will be visible to the other thread which reads that value from it. The variable may be of type `int` and it won't matter. – Marko Topolnik Feb 11 '15 at 21:22
  • `Whatever a thread wrote before assigning to a volatile`. In my example this is the `ImmutableArray`...so if I have understood, the JIT compiler has seen that the `ints` array has been set as a member (could be a setter instead of a constructor) of the `ImmutableArray` which has been set to a volatile variable and has ensured that both the `ints` array values and the `ImmutableArray` are thread visible...so, after I set the volatile reference, I could have Thread B read the `ints` array directly (not as a member of the `ImmutableArray`) and its contents will be thread visible? - correct? – Cheetah Feb 11 '15 at 22:31
  • The Java Memory Model (JMM) doesn't even know about objects. So what the model saw was that your thread A did some inter-thread *store* actions (writing to instance vars/array members) before doing a *synchronization action* (volatile write). Further it saw that your thread B did a matching synchronization action (volatile read) and then proceeded to do some other inter-thread *load* actions. The JMM gives you the guarantee that all these *load* actions by thread B after the volatile read will observe the effects of all the *store* actions done by thread A prior to the volatile write. – Marko Topolnik Feb 12 '15 at 07:54
  • So it has nothing to do with the fact that the writes and reads are related and that volatile is acting as a sort of barrier? (see last edit of OP)? – Cheetah Feb 12 '15 at 09:30
  • Until you stop leaning against the misleading paradigms of barriers, cache flushes, and so on, you won't be able to tune into the precise guarantees of the JMM. In your EDIT 2, the order of read actions is such that `a == 1` has no guarantee of evaluating to `true`. – Marko Topolnik Feb 12 '15 at 09:42
  • So if I read `b` first then the JMM would ensure that `a == 1` evaluated to true? – Cheetah Feb 12 '15 at 13:57
  • Yes. `b` is volatile. – Marko Topolnik Feb 12 '15 at 14:00