为什么Java ExecutorService执行采用新的Runnable实现

Cyr*_*ian 1 java multithreading

在下面的指定代码段中:

private ExecutorService executor = Executors.newFixedThreadPool(2); //create a fixed thread pool

executor.execute(new Thread(() -> foo()));
executor.execute(new Thread(() -> foo()));
executor.execute(new Thread(() -> foo()));


Run Code Online (Sandbox Code Playgroud)

在上面的示例中,创建了2个或3个线程有多少个?

  • 2:因为执行程序池大小为2。
  • 3:如代码中所示,我执行了3次新线程。

为什么不executor.execute(Callable);呢?

T.J*_*der 5

从根本上讲:不要Thread与一起execute使用,请使用Runnable。如您所述,ExecutorService处理线程是的工作。

在上面的示例中,创建了2个或3个线程有多少个?

您已经在评论中澄清了您的意思是那里的操作系统线程。

两个或五个(全线或光纤)。几乎可以肯定不是三个。可能是一或四个。好的精确答案。:-)原因如下:

肯定要Thread创建三个实例,因为您要明确地这样做。这并不意味着已经创建了三个OS线程。JavaDoc for Thread没有明确指出在创建Thread对象时或稍后在start调用/ if时创建了操作系统线程,这很可能取决于实现。由于您从未致电start,我们不知道为这些Thread实例创建任何操作系统线程。

因此,就操作系统线程而言,可能是:

  • ExecutorService响应您已调用execute两次或多次的事实,创建和启动的只是一两个,创建服务时设置的限制是两个线程。最初,我假定在给定这三个调用后肯定会创建两个线程,但是Aleksandr Semyannikov评论中指出,ExecutorService可能不必创建两个线程。这些execute调用计划的工作只是一个方法调用(尽管我们不知道该方法需要花多长时间运行)。因此,它可能只能重用一个线程。我倾向于对此表示怀疑(我认为第一个线程仍将分配给第一个线程execute打电话给您第二个),但是我对此的信任度不超过60%。:-)如果它真的很重要,我会对其进行测试(尽管我暂时不确定如何测试它)。
  • 四或五个:三个由创建new Thread,另一个由创建和启动ExecutorService

我的钱是两个。

我认为我们可以排除三个。要获得答案三,ExecutorService实现必须使用您传递的线程,几乎可以肯定不会。


在我的Linux系统上,我可以确认我的Java版本以15个(!)线程开始,并且当上面的代码运行时,还会创建两个。我还可以确认这些线程是池线程,而不是中的线程new Thread。我使用了现成的代码:

import java.util.*;
import java.util.concurrent.*;

public class Example {
    private static void foo() {
        System.out.println(Thread.currentThread().getName());
    }
    public static void main(String[] args) throws Exception {
        System.out.println("Waiting...");
        Thread.currentThread().sleep(20000);
        System.out.println("Starting...");
        ExecutorService executor = Executors.newFixedThreadPool(2); //create a fixed thread pool

        executor.execute(new Thread(() -> foo()));
        executor.execute(new Thread(() -> foo()));
        executor.execute(new Thread(() -> foo()));
    }
}
Run Code Online (Sandbox Code Playgroud)

并在20秒钟内等待ps aux | grep java获取进程的PID和top -H -pPID(其中PID是pid)以查看线程。