javathreadpoolguavawaitcountdownlatch

guava ThreadPool+CountDownLatch encounters IllegalMonitorStateException


I was trying to test guava concurrent package, as below.

I expect that the created thread pool will execute the "Runnable" class instance and then wait for termination.

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;
public class MyTest {
    public static void main(String [] args) {
        final CountDownLatch latch = new CountDownLatch(2);
        ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("UseCountDownLatch").build();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                10,
                10,
                100,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(1),
                namedThreadFactory);
        executor.execute(new Runnable() {
            @Override
            public void run() {
                latch.countDown();
            }
        });
        try {
            executor.wait();
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

But in fact, it prints:

Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at UseCountDownLatch.main(MyTest.java:28)

If I remove the line of

executor.wait();

Then program hangs there, without stopping. So where did I get wrong to gracefully execute and finish the task in ThreadPool? How to fix it?

Thanks a lot.


Solution

  • The observation that you haven't incremented the count for the countdownLatch enough is correct, +1 from me. To fix it you could add another task like the Runnable you pass in to the execute method.

    For why you are getting the IllegalMonitorStateException: it's because you called wait on the executor without holding the implicit lock on the executor object. That isn't anything that would make sense for you to do here. Maybe you confused it with awaitTermination?

    boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException

    Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.

    But for this case just call shutdown on the executor so it will know that no new tasks are coming and it can terminate the worker threads once the running tasks complete.