按照示例代码我正在注入一个睡眠100毫秒的biconsumer
作为一组可完成的未来的完成动作。我已经使用whenCompleteAsync
方法,通过单独使用executorService
。 executorService
是ThreadPoolExecutor
,核心池大小为5,最大大小为5,队列长度为1。
public class CompleteTest {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(5, 5, 10,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(1));
ArrayList<CompletableFuture<String>> list = new ArrayList<>();
for (int i = 0; i <100; i++) {
CompletableFuture<String> stringCompletableFuture = new CompletableFuture<>();
stringCompletableFuture.whenCompleteAsync((e, a) -> {
System.out.println("Complete " + e);
try {
Thread.sleep(100);
} catch (InterruptedException e1) {e1.printStackTrace();}
}, executorService);
list.add(stringCompletableFuture);
}
for (int i = 0; i < list.size(); i++) {
list.get(i).complete(i + "");
}
}
}
当我运行代码时,即使我正在完成100个期货,也只会打印6个输出。这是5个核心线程和1个排队的线程。剩下的会怎么样?如果其他runnable由于队列已满而无法提交给执行程序服务,那么不应该有异常。?
输出
Complete 0
Complete 1
Complete 2
Complete 3
Complete 4
Complete 5
答案 0 :(得分:5)
抛出异常,异常完成CompletableFuture
,而不是您正在跟踪的任何内容。
您正在使用构造函数实例化和初始化ThreadPoolExecutor
,该构造函数使用仅抛出异常的默认RejectedExecutionHandler
。我们知道如果RejectedExecutionException
无法接受任务,则会引发ExecutorService
。那么添加的任务在哪里以及抛出的异常在哪里?
目前,所有链接都在whenCompleteAsync
内发生。当您拨打该号码时,您需要向接收者CompletableFuture
,stringCompletableFuture
添加一个从属。完成stringCompletableFuture
后(在这种情况下成功),它将创建一个新的CompletableFuture
(它返回)并尝试在给定的BiConsumer
上安排给定的ExecutorService
。
由于ExecutorService
的队列没有空格,它将调用RejectedExecutionHandler
,它将抛出RejectedExecutionException
。该异常在那时被捕获并用于completeExceptionally
将返回的CompletableFuture
。
换句话说,在for
循环中,捕获CompletableFuture
返回的whenCompleteAsync
,存储它,并打印出其状态。
ArrayList<CompletableFuture<String>> list = new ArrayList<>();
ArrayList<CompletableFuture<?>> dependents = new ArrayList<>();
for (int i = 0; i <100; i++) {
CompletableFuture<String> stringCompletableFuture = new CompletableFuture<>();
CompletableFuture<?> thisWillHaveException = stringCompletableFuture.whenCompleteAsync((e, a) -> {
System.out.println("Complete " + e);
try {
Thread.sleep(100);
} catch (InterruptedException e1) {e1.printStackTrace();}
}, executorService);
dependents.add(thisWillHaveException);
list.add(stringCompletableFuture);
}
for (int i = 0; i < list.size(); i++) {
list.get(i).complete(i + "");
}
Thread.sleep(2000);
dependents.forEach(cf -> {
cf.whenComplete((r, e) -> {
if (e != null)
System.out.println(cf + " " + e.getMessage());
});
});
你会注意到他们都是(除了之前成功打印的6个)以RejectedExecutionException
特殊完成。
...
java.util.concurrent.CompletableFuture@2d8e6db6[Completed exceptionally] java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.CompletableFuture$UniWhenComplete@3f91beef rejected from java.util.concurrent.ThreadPoolExecutor@4eec7777[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
java.util.concurrent.CompletableFuture@23ab930d[Completed exceptionally] java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.CompletableFuture$UniWhenComplete@1a6c5a9e rejected from java.util.concurrent.ThreadPoolExecutor@4eec7777[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]
java.util.concurrent.CompletableFuture@4534b60d[Completed exceptionally] java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.CompletableFuture$UniWhenComplete@37bba400 rejected from java.util.concurrent.ThreadPoolExecutor@4eec7777[Running, pool size = 5, active threads = 5, queued tasks = 1, completed tasks = 0]