5

您好,我认为使用 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()吗?我的测试方法是错误的还是我理解错误?

4

2 回答 2

4

睡眠线程不能用于完成另一个线程的工作(特别是一个线程不能为另一个线程睡眠)。当第一个线程进入睡眠状态时,只有 CPU 可以切换到第二个线程。

当您向 提供任务时CompletableFuture.supplyAsync(),它会转到ForkJoinPool具有与您的计算机 CPU 一样多的线程的默认实例。您手动将分配的三个线程设置为默认值ForkJoinPool,因此您的九个任务在它们之间平均分配:每个线程连续执行三个任务。所以,你有三秒钟的结果。

于 2016-08-26T15:46:28.230 回答
1

让我们算一下。如果您有 9 个任务并且每个任务休眠 1 秒并且您有 2 个处理器,那么您一次只能运行 2 个 1 秒休眠。运行 9 个任务,您至少经过 3 秒或最多经过 4 秒。

这与非阻塞 IO 不同,因为此 Runnable 线程受 CPU 限制,并且在完成之前不会放弃 CPU(尽管处于睡眠状态)。如果您查看诸如 RxJava 的 IO 线程池之类的东西,它会为每个任务创建一个线程,这对于 IO 任务(但不是 CPU 绑定任务)是可以接受的。

于 2016-08-26T16:00:55.377 回答