Mia*_*ach 3 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"};
Run Code Online (Sandbox Code Playgroud)
据我所理解.
列表和数组中的初始值正确发布,并且对所有读取线程都可见.
初始化后添加的所有值都不是安全发布的.
我们仍然可以安全地阅读和发布它们
//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];
}
Run Code Online (Sandbox Code Playgroud)
我对吗?
严格看待代码正在做什么,仅此而已,仅根据内存模型评估它,你是对的.对publisher线程1中的volatile变量的写入和线程2中的volatile变量的读取建立了before-before关系,因此线程1的所有先前写入对于线程2的后续读取都是可见的.
正如CupawnTae所指出的那样,列表和数组不必是易失性的,以便保持它.只publisher需要挥发.
从更广泛的角度来看,将此代码扩展到其他任何事情都非常困难.(抛开List返回的by Arrays.asList不能添加元素的事实;假设它是一个ArrayList替代.)假设线程1或其他一些线程,将希望继续向列表中添加元素.如果这恰好导致ArrayList重新分配其底层数组,则当线程2仍在读取先前添加的结果时,可能会发生这种情况.因此,线程2可能看到不一致的状态.
进一步假设线程1想要进行后续更新.它必须设置publisher为其他一些值,例如2.现在,读取线程如何知道要测试的正确值是什么?好吧,他们可以从其他一些易变量中读取预期值....
毫无疑问,可以构建一个方案,其中线程1可以随意写入列表(或数组),而线程2将永远不会看到任何除了一致的快照,但是你必须在每一步都非常小心内存可见性.在某一点上,使用锁更容易.
这是正确的,但是……
列表和数组上的关键字volatile在这里无关紧要 - 事实上,您在写入其他值volatile publisher 之后写入一个值,并在读取第二个线程中的其他值之前if在条件中读回该值,这保证了这些值之间的内存一致性线程。
如果您volatile从列表和数组中删除关键字,您的代码仍然是安全的。
如果删除publisher变量写入/读取,则add操作*和数组赋值不再安全。
是的,对变量的初始赋值也是安全的。
*正如 Stuart Marks 指出的那样,实际上在该特定列表上实际上是无效的,但我们假设它是一个 ArrayList
| 归档时间: |
|
| 查看次数: |
4261 次 |
| 最近记录: |