Home > front end >  Java non-final fields force visibility with another volatile field
Java non-final fields force visibility with another volatile field

Time:10-11

I have recently begun to understand how the Java Memory Model works (I don't fully yet).

I now understand that if I have non-final, non-volatile fields in my classes then it is possible for the value of those fields to not be immediately visible to other threads post construction e.g.

public class Example {
    Object a;
    Object b;

    public Example() {
      this.a = new Object();
      this.b = new Object();
    }
}

Example e = new Example();

// now imagine we are in another thread
e.a // could this in theory be null?
e.b // could this in theory be null?

What I'm not sure about is weather if I add a third volatile variable and set it at the end will the writes to a and b be guaranteed to be visible to other threads?

public class Example2 {
    Object a;
    Object b;
    volatile Object c;

    public Example2() {
      this.a = new Object();
      this.b = new Object();
      this.c = new Object();
    }
}

// some where else
Example2 e2 = new Example2();
// are e2.a and e2.b guaranteed to be visible to all other threads? I know (e2.c will be)

This is not something I particularly want to use but I want to understand what would happen in this case.

CodePudding user response:

The constructor runs in a single thread and the instance is not "visible" to other threads until the constructor completes.

So, in this example, a and b will only be seen in other threads as null if they are subsequently set to null post-constructor.

The volatile keyword addresses possible optimizations in which a thread may continue to use an old value for a field after it changes on another thread due to local caching of the value. By adding volatile to the field, such optimizations are disabled.

By the way, if there's a need to synchronize across threads, using volatile fields is not ideal. Using atomic classes or other constructs from java.util.concurrent is advisable.

CodePudding user response:

That is a misconception.

Already said is that a constructor is completed on accessing the object.

Not using volatile means that a thread may have a stale (not updated) value. volatile ensures that on a thread switch the thread's values of those fields are updated. The reason being that a thread may cache a memory access, and thus run into being out-of-date.

One might think that this is a high-level language specific stupidity, but in fact already machine language knows such things: the ARM processor has a LDEX (load exclusive) and STEX (store exclusive) where one later detects that someone else wrote to the variable first.

I believe it is sufficient to have one volatile field to keep all fields up-to-date, non-cached. (But that is a technicality.)

For a non-volatile, thus cached value, you could get:

Thread X       Thread Y
// a == 13     // a == 13
a *= 2;
// a == 26
               // a == 13
               a *= 3;
               // a == 39

Wait a bit for better experts to give their feedback. The above is just my perception of valatile.

  • Related