[英]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 內存模型不保證(據我所知)一個線程寫入的值對另一個線程可見,除非您同步訪問。
根據您真正想要完成的事情, java.util.concurrent
可能已經有一個類可以為您完成。 如果沒有,我仍然建議查看ConcurrentHashMap
的源代碼,因為您的代碼似乎在做與管理哈希表相同的事情。
我不確定是否只同步write
方法,而不同步read
方法是否可行。 並不是所有的后果都是什么,但至少它可能導致read
方法返回一些剛剛被write
覆蓋的值。
是的,因為在多 CPU/核心環境中仍然會發生糟糕的緩存交錯。 有幾種選擇可以避免它:
由於 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.