我的CHM定义如下。每当有任何更新时,我都会从单个后台线程调用setDataProcess
方法。我总是从多个读者线程中调用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中的任何更改都会立即显示给所有读者线程,或者我需要使用volatile吗?
答案 0 :(得分:4)
据我所知,您在read方法中使用CountDownLatch
等待计数达到零。计数显然是ProcessType
中的枚举常量数。如果CountDownLatch
已正确实施,那么问题不应该是问题,因为根据javadocs,应该有一个先发生过的关系:
内存一致性影响:在计数达到零之前,在调用
countDown()
之前的某个线程中的操作发生在之后的操作发生之后,从另一个中的相应await()
成功返回线程。
忽略CountDownLatch
因素,ConcurrentHashMap
在检索密钥时不会同步,但会检索与密钥对应的最新值。
检索操作(包括
get
)通常不会阻止,因此可能与更新操作重叠(包括put
和remove
)。 检索反映了最近已完成更新操作的结果。
这意味着线程所做的更改对于读取键的线程是可见的。但这两个人可以干涉。
答案 1 :(得分:2)
CountdownLatch确保在countDown之前的操作发生 - 在另一个线程从等待返回之前,Manouti said。
对于ConcurrentHashMap,the api documentation读取:
给定密钥的更新操作与报告更新值的该密钥的任何(非空)检索具有先发生关系。
应该可以处理对从中读取的线程的地图更改的可见性。
答案 2 :(得分:0)
由于变量的值(即地图内存中的位置)不会改变,所以我怀疑volatile
会在这里产生影响。地图对象一旦分配,就不会四处移动。
但是,一如既往存在潜在的时间问题:线程可以在您更改之前或之后读取值。基本上,concurrentHashMap
不会被销毁一次被多个线程使用。因此,这是一个必要的功能。但是,仅凭这一点并未真正解决线程可能需要的任何其他同步或通知要求才能成功协同工作。