我有以下代码:
@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()
方法在这种情况下被阻止了?
答案 0 :(得分:2)
来自documentation of signalAll():
的引用当调用此方法时,实现可能(通常会)要求当前线程保持与此Condition关联的锁。
来自documentation of ReentrantLock.newCondition():
的引用与内置监视器锁一起使用时,返回的Condition实例支持与Object监视方法(wait,notify和notifyAll)相同的用法。
如果在调用任何条件等待或信令方法时未保持此锁定,则抛出IllegalMonitorStateException。
不确定为什么在测试中没有抛出IllegalMonitorException,但是当它在条件上调用signalAll()
时,确定的是推送线程没有锁定。