无法理解Java线程耗时:1000线程为何远超预期快速完成?
问题
我创建了1000个线程,每个线程需执行约10秒的简单数学运算(期间不睡眠),但在我的6核Intel i7电脑上,程序竟在20秒内完成。我原本预期至少需要1000/6≈167秒,且输出显示每个线程确实运行了约10秒,请问这是怎么回事?
测试代码
public class test { public static void main(String args[]) throws Exception { long startTime = System.currentTimeMillis(); Thread[] threads = new Thread[1000]; for(int i = 0; i<1000; i++){ threads[i] = new Thread(()->doSomething(10)); threads[i].start(); } for(Thread t : threads){ t.join(); } long endTime = System.currentTimeMillis(); System.out.println("Time taken "+(endTime - startTime)/1000); } public static int doSomething(int seconds){ long st = System.currentTimeMillis(); long usageTimeInMillis = seconds*1000L; long startTime = System.currentTimeMillis(); int i = 0; while ((System.currentTimeMillis() - startTime) < usageTimeInMillis) { i++; } long lt = System.currentTimeMillis(); System.out.println("Done "+Thread.currentThread().getId()+" in "+(lt-st)/1000+" seconds "); return i; } }
部分输出示例
Done 48 in 10 seconds Done 36 in 10 seconds Done 597 in 10 seconds ... Done 206 in 10 seconds Done 217 in 10 seconds .... Done 462 in 10 seconds Time taken 17
原因分析
你的线程并没有真正持续执行10秒的CPU密集运算,而是在等待时间流逝。
看doSomething方法的逻辑:你用System.currentTimeMillis()判断循环是否继续,循环体只是简单的i++。但这个循环的实际CPU占用极低——每次循环里的操作都极快完成,线程大部分时间其实是在空闲状态,等着下一次时间检查。操作系统会把空闲出来的CPU时间片调度给其他线程,所以1000个线程其实是并发等待10秒的墙上时间,而不是同时占用CPU执行运算。
这里要区分两个核心概念:
- 墙上时间(Wall Clock Time):就是实际流逝的物理时间,比如程序总耗时17秒、每个线程输出的10秒都是这个时间。
- CPU时间(CPU Time):线程真正占用CPU执行指令的时间,你的每个线程的CPU时间其实远小于10秒。
6核CPU可以同时让大量线程"等待时间流逝",总耗时自然接近单个线程的等待时间,再加上线程创建、调度的少量开销,最终就是17-20秒左右。
如果要测试真正的CPU密集型任务,得让线程持续占用CPU,比如循环计算复杂的数学题(比如判断大质数、迭代计算圆周率),直到线程的累计CPU时间达到10秒,这时候总耗时才会接近你最初预期的1000/6≈167秒。
内容的提问来源于stack exchange,提问作者Priyshrm
相关产品推荐
相关产品推荐

