对 ConcurrentHashMap 的写入是否立即可用于所有后续 servlet 请求?

Is a write to ConcurrentHashMap immediately available to all subsequent servlet requests?

假设只有一个服务器(没有负载均衡器等),如果 Java servlet 中的请求写入 static ConcurrentHashMap,映射条目是否立即可用于所有后续 servlet 请求,直到条目已从地图中删除?换句话说,在对映射的写入返回后,来自另一个 servlet 请求的后续请求是否有可能找不到任何映射?例如:

import java.util.concurrent.ConcurrentHashMap;

public class IntentTracker {
    
    private static ConcurrentHashMap<String, AccountUpdateRequest> updateForIntent = new ConcurrentHashMap<>();
    
    // static access only
    private IntentTracker() {}

    public static void put(String intentId, AccountUpdateRequest accountUpdate) {
        updateForIntent.put(intentId, accountUpdate);
    }
    
    public static AccountUpdateRequest remove(String intentId) {
        return updateForIntent.remove(intentId);
    }

} 

我知道这里的理想情况是使用持久性数据存储进行存储和检索,但我想了解 ConcurrentHashMap 是否会在此处引起问题。

Assuming a single server (no load balancer etc.), if a request in a Java servlet writes to a static ConcurrentHashMap, is the map entry immediately available to all subsequent servlet requests until the entry is removed from the map?

多线程编程中的一个问题是定义“后续”和描述事件的时间顺序的类似术语。 ConcurrentHashMap 做出的一些相关承诺是

  • 所有线程将感知相同的单元素映射修改顺序。
  • 所有线程都会观察到与修改顺序一致的单元素检索顺序。
  • Iterators, Spliterators, and Enumerations 的地图内容将反映地图在某个特定时间点相对于单个顺序的状态-元素修改。 (没有保证这个时间点与迭代器的实例化相关,etc..)

The specs 说...

Retrievals reflect the results of the most recently completed update operations holding upon their onset.

...但这必须被视为意向声明,而不是规范。紧随其后的是对实际含义的更正式的表达:

an update operation for a given key bears a happens-before relation with any (non-null) retrieval for that key reporting the updated value

在实践中,目的是提供您想要看到的行为,但从逻辑上反过来看更正确:在没有任何其他修改的情况下,一个线程的读取操作是否 R 感知到由不同线程执行的映射的特定修改 W 定义 是否 R 发生在 W.

之前或之后

In order words is there any possibility that, after a write to the map has returned, a subsequent request from another servlet request could find nothing for the mapping?

如果我们使用“后续”的适当定义,那么答案显然是“否”,因为请求是否为“后续”是由定义的(除其他事项外)一个请求是否看到另一个请求对地图的修改。但是,如果一个线程 确实 看到了那个修改(或者另一个在地图修改的全局一致顺序之后发生的),那么它也会看到共享内存上的所有其他操作其他在修改地图之前执行。

这并不意味着您必须担心在一个线程对地图的修改对其他线程可见之前会有很长的延迟。你不。关于单元素操作的时间和内存排序考虑与使用普通 HashMap 并在互斥锁保护下执行每次更新和每次读取非常相同,但通常 [ 不涉及锁定=10=].