簡體   English   中英

數組在 Java 中是線程安全的嗎?

[英]Are arrays thread-safe in Java?

只要索引不同,一個線程從數組的一個索引讀取,而另一個線程寫入數組的另一個索引,是否存在任何並發問題?

eg(這個例子不一定推薦實際使用,只是為了說明我的觀點)

 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);
     }     
 }

編輯:批評這個例子不是我的問題,我只是想知道數組訪問一個索引,同時訪問另一個索引,是否會造成並發問題,想不出一個簡單的例子。

雖然您不會像您提到的那樣通過更改數組來獲得無效狀態,但是當兩個線程在沒有同步的情況下查看非易失性整數時,您會遇到同樣的問題(請參閱 Java 教程中關於內存一致性錯誤的部分)。 基本上,問題在於線程 1 可能會在空間 i 中寫入一個值,但無法保證線程 2 何時(或是否)會看到更改。

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

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

這個問題的答案是數組的不同元素是獨立訪問的,因此如果兩個線程更改不同的元素,則不需要同步。

但是,Java 內存模型不保證(據我所知)一個線程寫入的值對另一個線程可見,除非您同步訪問。

根據您真正想要完成的事情, java.util.concurrent可能已經有一個類可以為您完成。 如果沒有,我仍然建議查看ConcurrentHashMap的源代碼,因為您的代碼似乎在做與管理哈希表相同的事情。

我不確定是否只同步write方法,而不同步read方法是否可行。 並不是所有的后果都是什么,但至少它可能導致read方法返回一些剛剛被write覆蓋的值。

是的,因為在多 CPU/核心環境中仍然會發生糟糕的緩存交錯。 有幾種選擇可以避免它:

  • 使用 Unsafe Sun-private 庫以原子方式設置數組中的元素(或 Java7 中的 jsr166y 添加功能
  • 使用 AtomicXYZ[] 數組
  • 將自定義對象與一個可變字段一起使用,並擁有該對象的數組。
  • 在您的算法中使用 jsr166y 附錄的 ParallelArray

由於 read() 未同步,您可能會遇到以下情況:

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();

既然你想保證你的變量地址永遠不會沖突,那么類似的事情呢(折扣數組索引問題):

int i;
synchronized int curr(){ return i; }
synchronized int next(){ return ++i;}

int read( ) {
         return values[curr()];
     }

void write(int x){
   values[next()]=x;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM