Condition instance signal All () does not return

I have the following code:

@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 );
}

      

Based on logs from test as below:

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

      

it seems like it hasItem.signalAll()

never came back as the magazine was signaled all threads

never released. Another clue is that the program only exited when the 20 second timeout was reached. So why is the method signalAll()

blocked in this case?

0


source to share


1 answer


Quoting from the signalAll () documentation :

An implementation can (and usually) require the current thread to hold the lock associated with this Condition when this method is called.

Quoting from the ReentrantLock.newCondition () documentation :



The returned condition instance supports the same usages as the object monitoring methods (wait, notify, and notifyAll) when used with the built-in monitor lock.

If this lock is not held when any of the wait or signaling methods are called, then an IllegalMonitorStateException is thrown.

Not sure why IllegalMonitorException is not thrown in your test, but what is certain is that the placing thread does not hold the lock when it calls signalAll()

on the condition.

EDIT: As @Fildor mentions, the exception was probably thrown, but swallowed by an empty catch block in your test. Do not use empty blocking blocks. If you throw an exception at runtime, excluding the caught exception instead of swallowing it, the problem becomes apparent.

+2


source







All Articles