Java 为什么线程10000次start()调用要比10000次run()调用花费更多的时间?
我在线程上做一个hello world,我使用Java 为什么线程10000次start()调用要比10000次run()调用花费更多的时间?,java,multithreading,Java,Multithreading,我在线程上做一个hello world,我使用run()调用创建了一个简单的线程(这只是一个普通的方法调用),使用start()调用创建了一个重复的线程,该调用生成了另一个线程来处理,但是start()调用所花费的时间比run()调用所花费的时间要多调用,不是线程调用,为什么会这样 开始通话时间:00:00:08:300 long time = System.currentTimeMillis(); for (int i = 0; i < 100000; i++) {
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"));
long time=System.currentTimeMillis();
对于(int i=0;i<100000;i++){
螺纹=新螺纹(新车());
setName(Integer.toString(i));
thread.start();
}
long completedIn=System.currentTimeMillis()-时间;
System.out.println(DurationFormatUtils.formatDuration(completedIn,
"HH:mm:ss:ss);;
运行调用时间: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"));
long time=System.currentTimeMillis();
对于(int i=0;i<100000;i++){
螺纹=新螺纹(新车());
setName(Integer.toString(i));
thread.run();
}
long completedIn=System.currentTimeMillis()-时间;
System.out.println(DurationFormatUtils.formatDuration(completedIn,
"HH:mm:ss:ss);;
实际创建一个新线程(重操作),而run
调用当前线程上线程对象的方法run
(简单方法调用-轻操作)
从关于开始的线程文档中:
使该线程开始执行;Java虚拟机调用
此线程的run方法。结果是有两个线程被删除
并发运行:当前线程(从调用返回)
到start方法)和另一个线程(执行其运行)
方法)
当您启动一组线程并且只有一个或两个内核时,上下文切换加上运行任务所花费的时间很容易超过一个任务接一个任务顺序运行代码所花费的时间。启动方法就是神奇之处。它会生成一个新线程,这需要时间:
- 创建线程
- 开线
- 管理线程生命周期
最好的解释可以在java.lang.Thread
的源代码中找到,您不应该直接调用run
。你在那里做的是创建一堆Thread
对象,但你从来没有真正创建过新线程;您只需在主线程上运行代码(因为您直接调用run
)
创建100000个线程在大多数当前计算机上都不会有好的表现(我不考虑价值数百万美元的高端计算机)。一旦您的线程数量超过了您所能支持的CPU容量,您就开始导致上下文切换。因此,如果您有一个四核系统,运行四个以上的线程实际上会降低您的程序速度(模数I/O操作,以及CPU将处于空闲状态的情况)。从评论到公认的回答:“您对此有什么建议吗?”
是的,不要直接使用线程。自Java5以来,我们有了java.util.concurrent框架,它允许简化线程和任务管理
创建线程的成本很高。甚至在线程运行您想要的任务之前,就必须创建它,这是一个非常长的过程。正是由于这个原因,我们有了线程池的概念。与每次要执行并发任务时都创建新线程不同,您首先创建所需的线程,以便它们准备就绪,并在需要时向它们发送任务。作为第二种选择的线程池。当任务完成时,线程不会被销毁,而是保持活动状态以运行下一个任务,因此线程创建成本只在初始化时发生一次
那么你如何使用这些概念呢
首先使用线程池创建一个执行器。为了保持简单,我们创建了一个包含100个线程的线程池(因为您希望模拟100个并发调用的负载):
然后你将提交你的任务:
long time = System.currentTimeMillis();
for (int i=0; i<100000; i++) {
pool.execute(new Car());
}
在线程代码中,您没有等待线程完成其任务,事实上,您测量的是线程创建时间,而不是任务运行时间
代码的作用是什么
executor.execute方法在线程内执行提供的任务。在这里,它使用100个线程中的一个,让它执行任务
如果有100多个任务,会发生什么
对于100个线程,您不能运行超过100个并发任务。其他任务将排队,直到一个任务完成,以便有一个线程可以执行它。这是一个很好的方法,可以确保您不会创建太多线程,并且不会发生OutOfMemory或其他讨厌的事情
你应该用多少线
这取决于您希望执行的任务类型
如果它像一个web服务器,那么您大部分时间都在IO绑定中等待数据库获取数据,然后等待网络发送响应,您的线程大部分时间都在等待。因此,即使是一个CPU也会从十几个甚至几百个线程中受益。即使更多的线程开始减慢整个应用程序的速度,它也允许处理用户请求,而不是让它等待,或者只是拒绝响应
如果您的任务受CPU限制,那么您可能希望每个CPU核心有一个任务,以便最大限度地利用硬件,但限制上下文切换的开销。使用4核超线程CPU,最多可以执行8个并发线程
这个回答只是一个简短的介绍。。。通过查看java.util.concurrent包和阅读一些教程,您将了解更多信息。run方法是线程启动的方法,但它只是Runnable接口的一个简单方法
start()方法将创建一个新线程(执行线程,一个真正的线程),该线程将执行线程实例的run()方法
可以在线程实例上调用run()方法,因为
long time = System.currentTimeMillis();
for (int i=0; i<100000; i++) {
pool.execute(new Car());
}
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"));
public void run() {
if (target != null) {
target.run();
}
}