为什么线程10000 start()调用比10000 run()调用花费更多时间?

Oh *_*oon 6 java multithreading

我在线程上做了一个hello world,我创建了一个使用该run()调用的简单线程(它只是一个普通的方法调用)和一个使用start()调用的复制线程,它产生另一个要处理的线程,但是,start()调用所花费的时间多于run()调用所采用的时间,这不是线程调用,为什么会这样?

开始通话时间:00:00:08:300

    long time = System.currentTimeMillis();

    for (int i = 0; i < 100000; i++) {
        Thread thread = new Thread(new Car());
        thread.setName(Integer.toString(i));
        thread.start();
    }

    long completedIn = System.currentTimeMillis() - time;

    System.out.println(DurationFormatUtils.formatDuration(completedIn,
            "HH:mm:ss:SS"));
Run Code Online (Sandbox Code Playgroud)

运行通话时间:00:00:01:366

    long time = System.currentTimeMillis();

    for (int i = 0; i < 100000; i++) {
        Thread thread = new Thread(new Car());
        thread.setName(Integer.toString(i));
        thread.run();
    }

    long completedIn = System.currentTimeMillis() - time;

    System.out.println(DurationFormatUtils.formatDuration(completedIn,
            "HH:mm:ss:SS"));
Run Code Online (Sandbox Code Playgroud)

MBy*_*ByD 6

start实际创建一个新的线程(繁重的操作),同时run调用run当前线程上的线程对象的方法(简单的方法调用 - 轻操作)

来自Thread的文档start:

导致此线程开始执行; Java虚拟机调用此线程的run方法.结果是两个线程并发运行:当前线程(从调用start方法返回)和另一个线程(执行其run方法).


Nic*_*uet 6

从评论到接受的回复:"你对此有什么建议吗?"

是的,不要直接使用线程.从java 5开始,我们有了java.util.concurrent框架,它允许简化线程和任务管理.

创建一个线程是昂贵的.即使在线程运行您想要的任务之前,它也必须被创建,这是一个非常漫长的过程.出于这个原因,我们有线程池的概念.您不必每次要执行并发任务时创建新线程,而是创建您需要的线程,以便它们准备就绪,并且您也可以在需要时向它们发送任务.一个线程池作为第二个adventage.任务完成后,线程不会被销毁,但会保持活动状态以运行下一个任务,因此在初始化时,线程创建成本只会发生一次.

那么你如何使用这些概念呢?

首先使用线程池创建一个执行程序.为了保持简单,我们创建了一个包含100个线程的线程池(因为你想模拟100个并发调用的加载):

ExecutorService pool = Executors.newFixedThreadPool(100);
Run Code Online (Sandbox Code Playgroud)

然后你提交你的任务:

long time = System.currentTimeMillis();
for (int i=0; i<100000; i++) {
  pool.execute(new Car());
}
Run Code Online (Sandbox Code Playgroud)

而且重要的是,在停止程序之前,您将等待所有任务完成!

pool.shutdown(); //Do no longer accept new tasks.
pool.awaitTermination(1, TimeUnit.HOURS); //Wait for up to one hour for all tasks to finish.
long completedIn = System.currentTimeMillis() - time;
System.out.println(DurationFormatUtils.formatDuration(completedIn,
            "HH:mm:ss:SS"));
Run Code Online (Sandbox Code Playgroud)

在您的线程代码中,您没有等待线程完成其工作,实际上您已经确定了线程创建时间,而不是任务运行时间.

代码做什么?

executor.execute方法在线程内执行提供的任务.这里需要100个线程中的一个,让它执行任务.

如果有超过100个任务会怎样?

使用100个线程,您无法运行超过100个并发任务.其他任务将排队,直到一个任务完成,因此一个线程可用于执行它.这是确保您不会创建太多线程和OutOfMemory或其他令人讨厌的事情不会发生的好方法.

你应该使用多少个线程?

这取决于您要执行的任务类型.

如果它就像一个Web服务器,你主要是IO绑定等待数据库获取数据,然后网络发送响应,你的线程将主要等待.因此,即使一个CPU也可以从十几个,甚至一百个线程中受益.即使更多线程开始减慢整个应用程序的速度,它也允许处理用户请求而不是让它等待,或者只是拒绝响应.

如果您的任务受CPU限制,那么您将需要每个CPU核心一个任务,以便最大限度地利用硬件但限制上下文切换的开销.使用4核超线程CPU,您最多可以使用8个并发线程.

这个回复只是一个简短的介绍...您将通过查看java.util.concurrent包并阅读一些教程来了解更多信息.