假设我有一个数据数组,2个线程可以安全地同时写入同一个数组的不同索引吗?我关心写入速度,我想同步'get index to write at'位与实际写入。
我正在编写代码,让我假设2个线程不会获得相同的索引。
答案 0 :(得分:34)
对于数组中的两个不同索引,相同的规则适用于两个单独的变量。
Java语言规范中的章节"Threads and Locks"首先说明:
17.4.1共享变量
[...]
所有实例字段,静态字段和数组元素都存储在堆内存中。 在本章中,我们使用术语变量来引用字段和数组元素。
这意味着您可以安全地同时写入两个不同的索引。 但是如果要确保使用者线程看到生产者线程写入的最后一个值,则需要将写入/读取同步到同一索引。
答案 1 :(得分:11)
在两个不同的线程中修改两个不同的变量是安全的。可以将修改阵列中的两个不同元素与在不同存储器地址下修改两个不同变量进行比较,至少就OS而言。所以是,这是安全的。
答案 2 :(得分:1)
嗯,是的,这在技术上是正确的,但这个答案有很多警告,让我感到非常担心,告诉你是的。因为虽然您可以写入数组中的两个不同位置,但如果不遇到并发问题,则无法执行其他操作。真正的问题在于,如果你能做到这一点,接下来要做什么?
如果您的计数器变量在数组写入不同位置时移动,则可能会遇到并发问题。当你的数组填满时,你可能有两个线程尝试写入同一个位置。如果你可能有一个数组的读者可以读取正在写入的相同位置,那么你将遇到并发问题。因此,如果您从未计划阅读它,那么写不会做任何事情,我认为当你去添加阅读器时(你将不得不锁定你的作家)你会遇到并发问题。那么问题是你是否没有移动线程所写的内容以阻止它写入数据?如果你没有移动线程写入的头部为什么使用数组?只是给他们各自的Latches或他们自己的变量写入,并真正保持它们分开。
如果没有全面了解你的意图,说“是”可能会让你陷入危险而不考虑你为什么要做你正在做的事情。
答案 3 :(得分:0)
如果您对arrayList没问题,请查看CopyOnWriteArrayList。来自其文档,
ArrayList的线程安全变体,其中包含所有可变操作 (添加,设置等)是通过制作新的副本来实现的 底层数组。
这通常成本太高,但可能比替代品更有效 当遍历操作数量远远超过突变时,并且在有效时非常有用 你不能或不想同步遍历,但需要排除 并发线程之间的干扰。
并且
CopyOnWriteArrayList的实例表现为List实现 允许多个并发读取,并允许读取与a同时发生 写。它的方式是每次都制作一个全新的列表副本 它被改变了。
读取不会阻塞,并且只能有效地支付易失性读取的成本; 写入不会阻止读取(反之亦然),但一次只能进行一次写入。