在Java中,如果每个线程写入单独的单元格空间,是否需要同步对数组的写访问?

如果每个线程写入单独的单元格空间,是否需要在Java中同步对数组的写访问权限?

编辑:具体来说,数组是原始数组或不可变对象数组。 防爆。 一个int数组或一个String数组。

不,不需要同步。

它在JLS§17.6字撕裂中定义:

Java虚拟机的一个实现考虑因素是每个字段和数组元素都被认为是不同的; 对一个字段或元素的更新不得与任何其他字段或元素的读取或更新交互。 特别是,分别更新字节数组的相邻元素的两个线程不得干涉或交互,也不需要同步以确保顺序一致性。

如果读取访问也以相同的方式分区,则根据bkail的链接不需要同步。

但是如果线程读取彼此的写入,则仍然需要具有内存屏障来强制缓存内容的同步。 否则,threadys可能会得到不一致的读取结果。

不是简单的是或否问题。 有些事情需要考虑:

  • 您的问题意味着您在数组中存储基元类型(或引用)。 对存储在arrays中的对象执行复杂操作可能需要同步。
  • 如果没有同步,更改longdouble值是不安全的
  • 即使您正在存储不是 doublelong基元,也有可能由于缓存而导致另一个线程无法立即看到更改的值(导致过时的读取

如果您希望其他线程始终能够看到您编写的最后一个值,则通常需要进行同步。 但是我可以在某些情况下,例如,预先计算一个巨大的long [] (每个条目需要占用大量的CPU),并且你将从几个线程中做到这一点,因为知道这些线程中没有两个会写入到同一个细胞。 然后,一旦完成所有线程,您将使用同步一次,以确保每次后续读取都会看到正确的值。 这样的事情。

请注意,如果您不想处理同步问题,可能需要查看AtomicLongArray等类。 作为一个额外的好处,像AtomicLongArray这样的类可能会得到一个不可能在100%Java中重新创建的实现的支持。

相同的线程是否也在读取值。 如果是这样,那你就可以了。 如果没有,那么您需要担心其他线程是否看到最新的值。 这通常通过关键工作volatile或通过primefaces变量来处理。

 For example if you have an int [] intArray with three elements. thread 1 updates intArray[0]= thread 2 updates intArray[1]= thread 3 updates intArray[2]= 

如果这些线程也用于读取值,那么你没问题但是如果新线程 – >线程4尝试读取值,则无法保证它将看到最新的赋值。

如果你使用AtomicIntegerArray,AtomicLongArray或AtomicReferenceArray,你会没事的

您可以执行您所要求的操作,更新每个索引所包含的内容, 但不能保证读取索引中的数据的其他线程正在查看当前数据。

Java中有一个名为volatile的关键字,用于标记实例和类变量,以便JVM知道这些值会发生变化,并且不会执行任何读取缓存优化, 因为读取线程可能会获得过时的数据 。 由于您无法标记数组索引内容,因此其他读者可以获得过时的数据。

在Java中使用原始Arrays只是在非常特定的场景中的好习惯。 您可能是其中一种情况,但我无法从问题中得知,因此我建议您专门在CopyOnWriteArrayList和CopyOnWriteArraySet中查看java.util.concurrent ,如果您不需要重复项。

由于某种原因,它们是标准库的一部分,如果您正在进行繁重的线程和数据共享,您应该尽可能熟悉java.util.concurrent

类似的问题提到了Concurrency Interest邮件列表 – “ primefaces字节[]操作? ”。

大卫霍姆斯说:

读/写数组的不同区域应该像访问独立数组一样。 这就是“没有语言撕裂”的保证。 无论VM如何实现arrays,VM都必须确保它适用于基本arrays访问。

正如我所说,如果涉及到本机版本的arraycopy,则不太清楚。

不要直接写入共享资源。 你将使multithreading程序比单线程计数器部分表现更差。 缓存作为缓存中的碎片效应被取出并在块中无效。 如果你想了解更多信息,请查看此演讲。 使用volatile和Synchronize比使用什么更好,但仍然很慢。

 https://www.youtube.com/watch?v=VCattsfHR4o 

我准备在这个主题上添加一个问题。 我做了一个测试,在访问数组时强制争用。 既控制协调访问,也使用非同步读 – 修改 – 写操作,如index–。

使用索引时 – 某些计数器> 1(全部应为1,否则互斥会破坏)

 public class App { static int threads = 1000; static int maxIndex = 1000; public static void main(String[] args) { try { testThreads(); } catch (InterruptedException ex) { Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex); } return; } public static void testThreads() throws InterruptedException { AtomicInteger[] ids = new AtomicInteger[maxIndex]; for (int i = 0; i < maxIndex; i++) { ids[i] = new AtomicInteger(0); } Executor exec = Executors.newFixedThreadPool(threads); AtomicInteger index = new AtomicInteger(maxIndex); final CountDownLatch startGate = new CountDownLatch(1); final CountDownLatch endGate = new CountDownLatch(threads); for (int i = 0; i < threads; i++) { exec.execute(new Runnable() { @Override public void run() { try { startGate.await(); try { int i = maxIndex; while (i > 0) { /** * Interchanging this lines force or avoid collisions. */ // i = --maxIndex; i = index.decrementAndGet(); ids[i].incrementAndGet(); } } catch(Exception ignored) { System.out.println(ignored); } finally { endGate.countDown(); } } catch (InterruptedException ignored) { } } }); } startGate.countDown(); endGate.await(); System.out.println(new ArrayList(Arrays.asList(ids))); } } 

一般来说,是的。 请尝试使用Vector。