条件实例signalAll()不返回

时间:2014-10-05 18:04:09

标签: java concurrency

我有以下代码:

@Log4j
public class ItemStore {
    final Lock lock = new ReentrantLock();
    final Condition hasItem = lock.newCondition();

    private Map<String, String> store = new Hashtable<>();

    public void put( String handle, String item) {
        store.put( handle, item );
        log.info("stored " + handle );
        hasItem.signalAll();
        log.info("signaled all threads");
    }

    public String fetchWithTimeout( String handle, long timeoutInSec ) throws InterruptedException {
        try {
            lock.lock();
            while ( !store.containsKey( handle ) ) {
                log.info("store doesn't have " + handle + "; keep waiting");
                hasItem.await( timeoutInSec, TimeUnit.SECONDS);
            }
            return store.get( handle );
        } finally {
            lock.unlock();
        }
    }
}



@Test
public void test_withPut() throws InterruptedException {
    ItemStore itemStore = new ItemStore();
    final String key = "foo";
    final String value = "bar";

    new Thread() {
        @Override
        public void run() {
            try {
                Thread.sleep(3000);
                log.info("slept 3 seconds");
                itemStore.put(key, value);
            } catch (Exception e) {
            }
        }
    }.start();

    log.info("fetching");
    String actual = itemStore.fetchWithTimeout(key, 20);
    log.info("actual = " + actual );
    assertEquals( actual, value );
}

根据测试日志如下:

2014-10-05 17:52:48 INFO  com.tns.ct.downloader.tests.commons.ItemStoreTest.test_withPut():36 - fetching
2014-10-05 17:52:48 INFO  com.tns.ct.downloader.tests.commons.ItemStore.fetchWithTimeout():30 - store doesn't have foo; keep waiting
2014-10-05 17:52:51 INFO  com.tns.ct.downloader.tests.commons.ItemStoreTest.run():29 - slept 3 seconds
2014-10-05 17:52:51 INFO  com.tns.ct.downloader.tests.commons.ItemStore.put():21 - stored foo
2014-10-05 17:53:08 INFO  com.tns.ct.downloader.tests.commons.ItemStoreTest.test_withPut():38 - actual = bar

似乎hasItem.signalAll()从未返回,因为signaled all threads日志从未发布过。另一个线索是程序仅在达到20秒超时时退出。那么,为什么signalAll()方法在这种情况下被阻止了?

1 个答案:

答案 0 :(得分:2)

来自documentation of signalAll()

的引用
  

当调用此方法时,实现可能(通常会)要求当前线程保持与此Condition关联的锁。

来自documentation of ReentrantLock.newCondition()

的引用
  

与内置监视器锁一起使用时,返回的Condition实例支持与Object监视方法(wait,notify和notifyAll)相同的用法。

     

如果在调用任何条件等待或信令方法时未保持此锁定,则抛出IllegalMonitorStateException。

不确定为什么在测试中没有抛出IllegalMonitorException,但是当它在条件上调用signalAll()时,确定的是推送线程没有锁定。

编辑:正如@Fildor所提到的,可能会引发异常,但是在测试中被空的catch块吞噬了。不要使用空的挡块。如果你抛出一个运行时异常包装捕获的异常而不是吞下它,问题就会变得很明显。