困惑于有条件地阻止线程的模式

时间:2012-09-04 13:38:13

标签: java concurrency

我有一个Map对象可能是null,或者只是在应用程序首次启动时清除。我需要访问此映射的所有线程阻塞,直到映射被初始化,然后我才需要通知所有线程来访问此映射。

此映射包含配置数据,除非单个线程决定刷新以加载新配置数据,否则它将仅用于读取(因此,为了提高性能,它不需要Synchronized,因为我没有找到必要的)。我尝试将Condition对象用于ReentrantLock,但每当我尝试IllegalMonitorStatesignalAll()时,它都会抛出await()个例外。

这是我需要做的伪代码:

void monitorThread{
    while(someCondition){
        map = updatedMap();
        condition.signalAll();
    }
}

String readValueFromMap(String key){
    if(map == null){
        condition.await();
    }
    return map.get(key);
}

3 个答案:

答案 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