2011-11-30 67 views
3

这个问题一再被问到,但我仍然有疑问。当人们说同步创建内存屏障时,这个内存屏障应用于什么,任何缓存变量?这看起来不太可行。Java数组:同步+原子*,或同步足够?

因此,由于这个疑问,我已经写了一些代码,看起来像这样:

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. 

我不知道是否有可能刚刚替补总的类型有普通的双[]:这将需要同步(总)(在run()方法中)确保我没有使用双精度数组中每个索引的本地副本,也就是说,内存围栏不仅适用于total本身的值在引擎盖下是一个指针),但也指向total。这是否发生?

回答

4

内存屏障适用于所有内存引用,甚至不相关的内存引用。当您同步total时,您将看到任何内存值的最新副本,而当您离开该块时,还有另一个内存障碍。

+0

谢谢,这真是我需要的答案。可惜这是我的第一个问题,所以我还没有投票。 –

+0

当你提到“*不相关的* ones”时,你的意思是**在synchronized块中的变量(但与* total *无关),对吧?即你并不是指与全局无关的那些(即与* total *无关并且与* total *用于同步​​,但被缓存并且在主存储器中具有过时值的块)无关。换句话说,你并不是指整个过程的所有缓存变量? (我知道这可能是一个愚蠢的问题,但只是为了确保......)。 –

+1

synchronized使用一个内存屏障来确保所有内存处于该线程的一致状态,无论该内存是否在该块内被引用。 –

0

如果我的理解是正确的synchronized(total)将同步任何访问total,因此应同步访问(读取和写入)的值在数组中了。

由于double数组直接包含值而不是引用,因此在执行同步块期间,其他线程不应该可以访问这些值。如果您有一个对象数组,您将无法更改数组中的引用,但仍然可以访问这些对象本身。

+0

问题是我需要互斥和最新值(和引用)。在你的回答中,你似乎只考虑了第一件事。 –