Search code examples
javaarraysatomicvolatilesynchronized

Java arrays: synchronized + Atomic*, or synchronized suffices?


This question has been asked again and again, but I have still a doubt. When people say that synchronized creates a memory barrier, what does this memory barrier apply to, ANY cached variable? This doesn't look like feasible.

So, due to this doubt, I have written some code that looks like this:

final AtomicReferenceArray<Double> total=new AtomicReferenceArray<Double>(func.outDim);
for(int i=0; i<func.outDim; i++) total.set(i, 0.);
for(int i=0; i<threads; i++){
    workers[i]=new Thread(new Runnable(){
        public void run() {
            double[] myPartialSum=new double(func.outDim);
            //some lengthy math which fills myPartialSum...

            //The Atomic* guarantees that I'm not writing local copies of the Double references (whose value are immutables, so it's like an array of truly volatile doubles) in variable total, synchronized(total) atomizes the sum
            synchronized(total){ for(int i=0; i<func.outDim; i++) total.set(i, total.get(i)+myPartialSum[i]); }
        };
    workers[i].start();
}
//wait for workers to terminate...

//print results accessing total outside of a synchronized(total) block, since no worker is alive at this point.

I wonder if it's possible to just substitute the type of total with a plain double[]: this would require that synchronized(total) (in the run() method) assures that I'm not working with local copies of each index in the array of doubles, that is, the memory fence does not apply only to the value of total itself (which is under the hood a pointer), but to the indexes of total too. Does this happen?


Solution

  • The memory barrier applies to all memory references, even unrelated ones. When you synchronize total you will see an up to date copy of any memory values and when you leave the block, there is another memory barrier.