Bhaskar
Bhaskar

Reputation: 7523

Volatile array - memory visibility of the elements

Consider the code snippet

class A {

   private Map<String, Object> taskMap = new HashMap<>();
   private volatile Object[] tasksArray ;

   // assume this happens on thread1 
   public void assignTasks() {
     synchronized(taskMap){
         // put new tasks into map
         // reassign values from map as a new array to tasksArray ( for direct random access )
     }

    }

   // assume this is invoked on Thread2
   public void action(){
       int someindex =  <init index to some value within tasksArray.length>;
       Object[] localTasksArray = tasksArray;
       Object oneTask = localTasksArray[someindex];
       // Question : is the above operation safe with respect to memory visibility for Object oneTask ?
       // is it possible that oneTask may appear null or in some other state than expected ?

   }

}

Question : is the operation Object oneTask = localTasksArray[someindex]; safe with respect to memory visibility for Object oneTask ? is it possible that oneTask may appear null or in some other state than expected ?

My thoughts are these :

It is possible that thread2 may see oneTask as null or in some state other than expected. This is because , even though the taskArray is volatile , and a read of this array will ensure proper visibility of the array itself , this does not ensure the visibility of the state internal to the object oneTask.

Upvotes: 4

Views: 739

Answers (3)

OldCurmudgeon
OldCurmudgeon

Reputation: 65879

As far as I recall (I am researching now to confirm), Java only guarantees the volatile object itself is flushed to RAM, not sub parts of that object (as in array entries) or sub-fields of the object (in the case of objects).

However - I believe most (if not all) JVMs implement volatile access as a memory barrier (see here and the referenced page The JSR-133 Cookbook for Compiler Writers). As a memory barrier this therefore means that all previous writes by other threads will be flushed from cache to main memory when the access occurs - thus making all memory consistent at that time.

This should not be relied upon - if it is crucial that you have complete control of what is visible and what is not you should use one of the Atomic classes such as AtomicReferenceArray as suggested by others. These may even be more efficient than volatile for exactly this reason.

Upvotes: 4

meriton
meriton

Reputation: 70584

Declaring a field volatile ensures that any write of that variable synchronizes-with (and is therefore visible to) any subsequent (according to synchronization order) of this value. Note that there is no such thing as a volatile object, or a volatile array. There are only volatile fields.

Therefore, in your code, there is no happens-before relationship between Thread 1 storing an object into the array, and Thread 2 reading it from there.

Upvotes: 2

Peter Lawrey
Peter Lawrey

Reputation: 533870

The volatile keyword only protects the field taskArray which is a reference to an Object[]. Whenever you read or write this field, it will have consistent ordering. However, this doesn't extend to the array referenced nor the objects that array references.

Most likely you want AtomicReferenceArray instead.

Upvotes: 5

Related Questions