可以同时等待和释放底层线程资源的线程间通信机制是什么

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

我正在寻找一种可以同时等待和释放底层线程资源的线程间通信机制。在我下面的示例中,当 executorService 仅使用 1 个线程初始化时,第二个任务将被卡住,因为线程被 t1 占用,即使它是 await。以下代码仅在您更改为使用 2 个线程初始化 executorService 时才有效。

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

executorService 初始化为 1 个线程时的输出。

start t1
Master thread ends

executorService初始化2个线程时的输出

start t1
Master thread ends
start t2
t2 done
t1 done

理想情况下,当 t1 等待时,它不需要持有底层线程,这样 task2 就可以 运行 在这个线程池中。这个问题的一个真实用例是,如果我有一个线程池,任务将 submitted/scheduled 返回到同一个池中进行重试。理论上,当所有提交的任务立即失败时,进程将被卡住,因为没有运行重试任务的线程。

创建一个单独的线程池进行重试可以解决这个问题,但是我想知道JAVA是否提供了一种线程间通信机制,允许同时等待和释放底层线程,这样只需要 1 个线程池。

释放底层线程资源的唯一方法是完全return从任务的主要方法(通常Runnable::run)。要同时等待,事件生产者应该以异步方式订阅。并非每个生产者都有异步接口。 CompletbleFuture 有(方法 whenComplete),但 CountDownLatch 没有。但是,您可以使用异步功能扩展 CountDownLatch,订阅其完成,return 来自 运行() 并等待。我在 DF4J library: AsyncCountDownLatch.java

中这样做了