在 ForkJoinpool 上使用 CompletableFuture 并避免线程等待
Use CompletableFuture on ForkJoinpool and avoid thread waiting
你好,我认为使用 CompletableFuture 和默认 ForkJoinPool
我可以比经典 ExecutorService
更优化任务的执行,但我遗漏了一些东西
使用此代码执行需要 1 秒,我有 3 个工作线程:
for (int i = 0; i < 3; i++) {
final int counter = i;
listTasks.add(CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
System.out.println("Looking up " + counter + " on thread " + Thread.currentThread().getName());
return null;
}));
}
好的,看起来很正常。
但是使用这段代码,需要 3 秒:
for (int i = 0; i < 9; i++) {
final int counter = i;
listTasks.add(CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
System.out.println("Looking up " + counter + " on thread " + Thread.currentThread().getName());
return null;
}));
}
我以为休眠线程会用来启动其他等待任务,应该也需要1秒。例如,我读过 IO WAINTING 线程状态意味着该线程可以重新用于其他任务。我可以用 Thread.sleep()
测试这种行为吗?是我测试方法不对还是我理解有误?
一个休眠线程不能用来做另一个线程的工作(特别是,一个线程不能为另一个线程休眠)。只有CPU可以在第一个线程休眠时切换到第二个线程。
当您向 CompletableFuture.supplyAsync()
提供任务时,它会转到 ForkJoinPool
的默认实例,该实例的线程数与您计算机的 CPU 线程数一样多。您手动将分配的三个线程设置为默认 ForkJoinPool
,因此您的九个任务在它们之间平均分配:每个线程连续执行三个任务。所以,你有三秒钟的时间作为结果。
让我们来计算一下。如果你有 9 个任务,每个任务休眠 1 秒,而你有 2 个处理器,你一次只能 运行 2 个 1 秒休眠。 运行 这有 9 个任务,你至少用了 3 秒或最多用了 4 秒。
这与非阻塞 IO 不同,因为这个 运行nable 线程是 CPU 绑定的并且不会放弃 CPU 直到它完成(尽管睡眠).如果你看一下 RxJava 的 IO 线程池之类的东西,它会为每个任务创建一个线程,这对 IO 任务来说是可以接受的(但 CPU 绑定任务)。
你好,我认为使用 CompletableFuture 和默认 ForkJoinPool
我可以比经典 ExecutorService
更优化任务的执行,但我遗漏了一些东西
使用此代码执行需要 1 秒,我有 3 个工作线程:
for (int i = 0; i < 3; i++) {
final int counter = i;
listTasks.add(CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
System.out.println("Looking up " + counter + " on thread " + Thread.currentThread().getName());
return null;
}));
}
好的,看起来很正常。
但是使用这段代码,需要 3 秒:
for (int i = 0; i < 9; i++) {
final int counter = i;
listTasks.add(CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
System.out.println("Looking up " + counter + " on thread " + Thread.currentThread().getName());
return null;
}));
}
我以为休眠线程会用来启动其他等待任务,应该也需要1秒。例如,我读过 IO WAINTING 线程状态意味着该线程可以重新用于其他任务。我可以用 Thread.sleep()
测试这种行为吗?是我测试方法不对还是我理解有误?
一个休眠线程不能用来做另一个线程的工作(特别是,一个线程不能为另一个线程休眠)。只有CPU可以在第一个线程休眠时切换到第二个线程。
当您向 CompletableFuture.supplyAsync()
提供任务时,它会转到 ForkJoinPool
的默认实例,该实例的线程数与您计算机的 CPU 线程数一样多。您手动将分配的三个线程设置为默认 ForkJoinPool
,因此您的九个任务在它们之间平均分配:每个线程连续执行三个任务。所以,你有三秒钟的时间作为结果。
让我们来计算一下。如果你有 9 个任务,每个任务休眠 1 秒,而你有 2 个处理器,你一次只能 运行 2 个 1 秒休眠。 运行 这有 9 个任务,你至少用了 3 秒或最多用了 4 秒。
这与非阻塞 IO 不同,因为这个 运行nable 线程是 CPU 绑定的并且不会放弃 CPU 直到它完成(尽管睡眠).如果你看一下 RxJava 的 IO 线程池之类的东西,它会为每个任务创建一个线程,这对 IO 任务来说是可以接受的(但 CPU 绑定任务)。