javamultithreadingthreadpoolthreadpoolexecutorcountdownlatch

What's the inter-thread communication mechanism that can await and release underlying thread resource at the same time


I am looking for an inter-thread communication mechanism that can await and release underlying thread resource at the same time. In my example below, when the executorService is initialized with only 1 thread, the second task will be stuck because the thread is held by t1 even though it's await. The code below will only work if you change to initialize the executorService with 2 threads.

public static void main(String[] args) {
  ExecutorService executorService = Executors.newFixedThreadPool(1);
  CountDownLatch cdl = new CountDownLatch(1);

  executorService.submit(() -> {
    System.out.println("start t1");
    try {
      cdl.await();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println("t1 done");
  });

  executorService.submit(() -> {
    System.out.println("start t2");
    cdl.countDown();
    System.out.println("t2 done");
  });

  System.out.println("Master thread ends");
}

The output when executorService is initialized with 1 thread.

start t1
Master thread ends

The output when executorService is initialized with 2 threads.

start t1
Master thread ends
start t2
t2 done
t1 done

Ideally, when t1 is waiting, it doesn't need to hold the underlying thread such that task2 can run within this thread pool. A real-world use case of this problem is that if I have a thread pool, and the tasks will be submitted/scheduled back to the same pool for retries. Theoretically, the process will be stuck when all tasks submitted failed immediately because there are no threads for running the retry tasks.

Creating a separate thread pool for retry can solve this problem, but I am wondering if JAVA provides an inter-thread communication mechanism that allows waiting and releasing the underlying thread at the same time, so that only 1 thread pool is needed.


Solution

  • The only way to release underlying thread resource is to completely return from the main method of the task (usually Runnable::run). To await at the same time, the event producer should be subscribed in asynchronous way. Not every producer has asynchronous interface. CompletbleFuture has (method whenComplete), but CountDownLatch has not. However, you can extend CountDownLatch with asynchronous finctionality, subscribe to its completion, return from run() and wait. I did so in my DF4J library: AsyncCountDownLatch.java