我有一个Map
对象可能是null
,或者只是在应用程序首次启动时清除。我需要访问此映射的所有线程阻塞,直到映射被初始化,然后我才需要通知所有线程来访问此映射。
此映射包含配置数据,除非单个线程决定刷新以加载新配置数据,否则它将仅用于读取(因此,为了提高性能,它不需要Synchronized
,因为我没有找到必要的)。我尝试将Condition
对象用于ReentrantLock
,但每当我尝试IllegalMonitorState
或signalAll()
时,它都会抛出await()
个例外。
这是我需要做的伪代码:
void monitorThread{
while(someCondition){
map = updatedMap();
condition.signalAll();
}
}
String readValueFromMap(String key){
if(map == null){
condition.await();
}
return map.get(key);
}
答案 0 :(得分:4)
CountDownLatch
就是你所需要的。
CountDownLatch latch = new CountDownLatch(1);
初始化hashmap时latch.countdown()
,在线程中使用latch.await()
void monitorThread{
map = updatedMap();
latch.countDown();
}
String readValueFromMap(String key){
latch.await();
return map.get(key);
}
请注意,CountDownLatch await()
方法仅在倒计时大于0时等待,因此只是第一次。
答案 1 :(得分:3)
要做到这一点,你需要一个内存屏障volatile
。因为最初的映射可能为null,所以您将需要另一个锁定对象。以下应该有效:
private final Object lockObject = new Object();
private volatile Map<...> map;
void monitorThread{
while (condition){
// do this outside of the synchronized in case it takes a while
Map<...> updatedMap = updatedMap();
synchronized (lockObject) {
map = updatedMap;
// notify everyone that may be waiting for the map to be initialized
lockObject.notifyAll();
}
}
}
String readValueFromMap(String key) {
// we grab a copy of the map to avoid race conditions in case the map is
// updated in the future
Map<...> mapRef = map;
// we have a while loop here to handle spurious signals
if (mapRef == null) {
synchronized (lockObject) {
while (map == null) {
// wait for the map to initialized
lockObject.wait();
}
mapRef = map;
}
}
return mapRef.get(key);
}
答案 2 :(得分:0)
听起来你只需要一个“锁定”对象来保护对Map的访问。
这些很容易使用:
Lock l = ...;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock();
}
您可以使用:java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock