Mar*_*šić 14 java multithreading concurrenthashmap memory-visibility
假设我有一个带有集合的并发映射值:
Map<Integer, List<Integer> map = new ConcurrentHashMap<>();
map.putIfAbsent(8, new ArrayList<>());
Run Code Online (Sandbox Code Playgroud)
我更新了如下值:
map.computeIfPresent(8, (i, c) -> {
c.add(5);
return c;
});
Run Code Online (Sandbox Code Playgroud)
我知道computeIfPresent
整个方法调用是以原子方式执行的.但是,考虑到这个映射是由多个线程同时访问的,我有点担心对底层集合所做的修改的数据可见性.在这种情况下,调用后将在列表中看到值5map.get
我的问题是map.get
如果在computeIfPresent
方法调用中执行了更改,则在调用时将更改为列表在其他线程中可见.
请注意,如果我在执行更新操作之前参考列表,我知道列表的更改将不可见.如果我map.get
在更新操作后引用列表(通过调用),我不确定列表的更改是否可见.
我不确定如何解释文档,但在我看来发生这种情况 - 在关系之前将保证在这种特定情况下对底层集合的更改的可见性
更正式地说,给定密钥的更新操作承担与该密钥的任何(非空)检索之前发生的关系,报告更新的值
您正在提供一些外部保证,例如before 调用的Map.computeIfPresent()
保证。 Map.get()
您还没有说明如何执行此操作,但假设您正在使用JVM 提供的“先发生”语义来执行此操作。如果是这种情况,那么仅通过关联发生之前List.add()
关系就可以保证线程调用可见。Map.get()
现在回答您实际提出的问题:正如您所注意到的,更新操作和访问方法的后续调用之间存在“发生之前”关系。自然地, 和的结尾之间存在发生在之前的关系。ConcurrentHashMap.computeIfPresent()
ConcurrentMap.get()
List.add()
ConcurrentHashMap.computeIfPresent()
综合起来,答案是肯定的。
如果您保证在结束后实际调用(如问题中所述),则可以保证其他线程将5
在List
获取的 through中看到。如果后一个保证出现问题并且在结束之前以某种方式被调用,则无法保证其他线程会看到什么,因为它不是线程安全的。Map.get()
Map.get()
computeIfPresent()
Map.get()
computeIfPresent()
ArrayList