2009-07-15 81 views
20

只要索引不同,是否有任何併發​​性問題與一個數組的一個索引讀取,而另一個線程寫入數組的另一個索引?java array thread-safety

例如(這個例子不一定推薦真正使用,只是爲了說明我的觀點)

class Test1 
{ 
    static final private int N = 4096; 
    final private int[] x = new int[N]; 
    final private AtomicInteger nwritten = new AtomicInteger(0); 
    // invariant: 
    // all values x[i] where 0 <= i < nwritten.get() are immutable 

    // read() is not synchronized since we want it to be fast 
    int read(int index) { 
     if (index >= nwritten.get()) 
      throw new IllegalArgumentException(); 
     return x[index]; 
    } 
    // write() is synchronized to handle multiple writers 
    // (using compare-and-set techniques to avoid blocking algorithms 
    // is nontrivial) 
    synchronized void write(int x_i) { 
     int index = nwriting.get(); 
     if (index >= N) 
      throw SomeExceptionThatIndicatesArrayIsFull(); 
     x[index] = x_i; 
     // from this point forward, x[index] is fixed in stone 
     nwriting.set(index+1); 
    }  
} 

編輯:批評這個例子是不是我的問題,我真的只是想知道一個索引,如果數組訪問,同時對訪問另一個索引引起併發性問題,無法想到一個簡單的例子。

回答

12

雖然你不會改變陣列得到一個無效狀態就像你提到的那樣,當兩個線程在不同步的情況下查看一個非易失性整數時,你將會遇到同樣的問題(請參閱Java教程Memory Consistency Errors中的部分)。基本上,問題是線程1可能會在空間i中寫入一個值,但不能保證何時(或如果)線程2會看到更改。

java.util.concurrent.atomic.AtomicIntegerArray做你想做的事。

+0

感謝... DRAT,我想用一個byte []數組,它看起來像有沒有這樣的原子動物....我想我會只使用同步方法並保持簡單。 – 2009-07-15 17:24:50

4

這個例子有很多不同於散文問題的東西。

這個問題的答案是數組的獨立元素是獨立訪問的,所以如果兩個線程改變不同的元素,你不需要同步。

但是,Java存儲器模型沒有保證(我知道)一個線程寫入的值對另一個線程是可見的,除非你同步訪問。

根據你真正想要完成的事情,很可能java.util.concurrent已經有一個類可以爲你做。如果沒有,我仍然建議看看ConcurrentHashMap的源代碼,因爲你的代碼看起來和管理哈希表的做法是一樣的。

1

我不確定如果只同步write方法,而使read方法不同步可以工作。實際上不會有什麼後果,但至少可能導致read方法返回一些剛剛被write覆蓋的值。

1

是的,因爲錯誤的高速緩存交錯仍然可能發生在多CPU /核心環境。有幾個選項來避免它:

  • 使用不安全的太陽私人圖書館以原子設置一個數組中的元素(或Java7
  • 使用AtomicXYZ []數組
  • 使用自定義的jsr166y附加功能有一種揮發性Field對象,並有對象的數組。
  • 使用jsr166y的齒頂的ParallelArray中,而不是你的算法
1

由於讀()不同步,你可以有以下的風光ARIO:

Thread A enters write() method 
Thread A writes to nwriting = 0; 
Thread B reads from nwriting =0; 
Thread A increments nwriting. nwriting=1 
Thread A exits write(); 

既然你要保證你的變量地址從來沒有衝突,怎麼樣像(扣除數組索引的問題):

​​3210
+0

感謝,但不是我的問題與你的情況是不可能發生的(步驟2和3永遠不會發生) – 2009-07-15 17:20:52