我有以下代码:
@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块吞没了。不要使用空的捕获块。如果您抛出包裹了捕获的异常而不是吞下捕获的异常的运行时异常,则问题将变得很明显。