ConcurrentHashMap 更改对所有线程可见?

ConcurrentHashMap changes visible to all the threads?

我有一个定义如下的 CHM。每当有任何更新时,我都会从单个后台线程调用 setDataProcess 方法。我总是从多个 reader 线程调用 getDataMapping

private static final ConcurrentHashMap<ProcessType, Mapping> mappingsHolder = new ConcurrentHashMap<ProcessType, Mapping>();
private static final CountDownLatch hasInitialized = new CountDownLatch(ProcessType.values().length);

public static void setDataProcess(ProcessType processType, Mapping newMapData) {
    mappingsHolder.put(processType, newMapData);
    hasInitialized.countDown();
}

public static Mapping getDataMapping(ProcessType processType) {
    try {
        hasInitialized.await();
        return mappingsHolder.get(processType);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new IllegalStateException(e);
    }
}

问题是 - mappingsHolder CHM 中的任何更改都会立即对所有 reader 线程可见,或者我需要为此使用 volatile 吗?

既然变量的值(即地图在内存中的位置)不会改变,那么我怀疑volatile会在这里有所作为。地图对象一旦分配,就不会再移动了。

但一如既往地存在潜在的计时问题:线程可能会在您更改值之前或之后读取它。基本上,一个 concurrentHashMap 不会因一次被多个线程使用而被 破坏 。因此,这是一个必要的功能。但是,仅此一项并不能真正解决线程为了成功协同工作可能需要的任何其他同步或通知要求。

据我所知,您在读取方法中使用了 CountDownLatch 来等待计数达到零。计数显然是 ProcessType 中枚举常量的数量。如果此 CountDownLatch 得到正确实施,应该不会有问题,因为根据 javadocs,应该存在先行关系:

Memory consistency effects: Until the count reaches zero, actions in a thread prior to calling countDown() happen-before actions following a successful return from a corresponding await() in another thread.

忽略 CountDownLatch 因素,ConcurrentHashMap 不会同步检索键,而是检索与键对应的最新值。

Retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove). Retrievals reflect the results of the most recently completed update operations holding upon their onset.

这意味着线程所做的更改对于读取密钥的线程是可见的。但是两者可以相互干扰。

CountdownLatch 确保在 countDown 之前的操作发生在另一个线程的 return 等待之前,如 .

关于 ConcurrentHashMap,the api documentation 为:

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

它应该处理映射更改对从中读取的线程的可见性。