java - 在 Java 中使用 volatile 集合和数组

标签 java collections concurrency volatile java-memory-model

假设我们有

volatile int publisher = 0;
volatile List<String> list = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
volatile String[] array = {"Buenos Aires", "Córdoba", "La Plata"};

据我了解。

列表和数组中的初始值被正确发布并且对所有读取线程可见。

初始化后添加的所有值都不是安全发布的。

我们仍然可以使用

安全地阅读和发布它们
//in Thread 1
list.add("Safe City");
array[2] = "Safe city";
publisher = 1;

//in Thread2

if(publisher == 1) {
String city = list.get(3);
city = array[2];
}

我说得对吗?

最佳答案

严格查看代码在做什么,仅此而已,并且仅根据内存模型对其进行评估,您是正确的。在线程 1 中写入 volatile 变量 publisher 和在线程 2 中读取 volatile 变量建立了一个happens-before 关系,因此所有先前从线程 1 的写入将是对线程 2 的后续读取可见。

正如 CupawnTae 指出的那样,列表和数组没有必要为了保持这一点而变得不稳定。只有 publisher 需要可变。

从更广泛的角度来看,很难扩展这段代码来做任何其他事情。 (撇开 Arrays.asList 返回的 List 不能添加元素这一事实;假设它是一个 ArrayList。)大概是线程1,或其他一些线程,将要继续向列表中添加元素。如果这恰好导致 ArrayList 重新分配其底层数组,则这可能会在线程 2 仍在读取上一次添加的结果时发生。因此,线程 2 可能会看到不一致的状态。

进一步假设线程1要进行后续更新。它必须将 publisher 设置为某个其他值,比如 2。现在读取线程如何知道要测试的正确值是什么?好吧,他们可以从其他一些可变变量中读取预期值....

毫无疑问,可以构造一个方案,其中线程 1 可以随意写入列表(或数组),而线程 2 除了一致的快照之外永远看不到任何东西,但是你必须在每一步都格外小心内存可见性道路。在某个时候,使用锁会更容易。

关于java - 在 Java 中使用 volatile 集合和数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25574797/

相关文章:

java - 为什么 Vector 方法 Iterator 和 ListIterator 快速失败

scala - Ref/MVar 的有效更新

c# - ASP.NET Web API C# 并发请求导致数据库重复

java - MotionEvent.obtain(…);不像屏幕上的攻丝

scala:如何将 ArrayBuffer 转换为 Set?

java - Debug模式超时 Tomcat

c# - 如何在 IEnumerable<T> 上实现 ICollection<T>

Java执行多个线程并等待完成

java - 在 Java 中将 ArrayList 作为泛型参数传递

java - 在后台线程上运行的进程仍然卡住UI