我有以下代码:

@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()方法被阻止?

最佳答案

引用documentation of signalAll()


  一个实现可能(并且通常确实)要求在调用此方法时当前线程持有与此Condition相关的锁。


引用documentation of ReentrantLock.newCondition()


  当与内置监视器锁定一起使用时,返回的Condition实例支持与Object监视器方法(wait,notify和notifyAll)相同的用法。
  
  如果在调用任何条件等待或信令方法时未保持此锁定,则将抛出IllegalMonitorStateException。


不知道为什么在测试中未抛出IllegalMonitorException,但是可以确定的是,在条件条件下调用signalAll()时,放置线程不会持有锁定。

编辑:正如@Fildor所提到的,可能抛出了一个异常,但被测试中的空catch块吞没了。不要使用空的捕获块。如果您抛出包裹了捕获的异常而不是吞下捕获的异常的运行时异常,则问题将变得很明显。

10-04 18:01