java数组线程安全

一个线程从数组的一个索引读取是否有任何并发​​问题,而另一个线程写入数组的另一个索引,只要索引不同?

例如(这个例子不一定推荐用于实际用途,仅用于说明我的观点)

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()) 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库以primefaces方式设置数组中的元素(或Java7中添加的jsr166yfunction)
  • 使用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; }