陷阱 - 线程创建相对昂贵

考虑这两个微基准:

第一个基准测试只是创建,启动和连接线程。线程的 Runnable 无效。

public class ThreadTest {
    public static void main(String[] args) throws Exception {
        while (true) {
            long start = System.nanoTime();
            for (int i = 0; i < 100_000; i++) {
                Thread t = new Thread(new Runnable() {
                        public void run() {
                }});
                t.start();
                t.join();
            }
            long end = System.nanoTime();
            System.out.println((end - start) / 100_000.0);
        }
    }
}

$ java ThreadTest 
34627.91355
33596.66021
33661.19084
33699.44895
33603.097
33759.3928
33671.5719
33619.46809
33679.92508
33500.32862
33409.70188
33475.70541
33925.87848
33672.89529
^C

在运行 Linux 64bit Java 8 u101 的典型现代 PC 上,此基准测试显示创建,启动和连接线程所需的平均时间在 33.6 和 33.9 微秒之间。

第二个基准测试与第一个相同,但使用 ExecutorService 提交任务,并使用 Future 与任务结束时会合。

import java.util.concurrent.*;

public class ExecutorTest {
    public static void main(String[] args) throws Exception {
        ExecutorService exec = Executors.newCachedThreadPool();
        while (true) {
            long start = System.nanoTime();
            for (int i = 0; i < 100_000; i++) {
                Future<?> future = exec.submit(new Runnable() {
                    public void run() {
                    }
                });
                future.get();
            }
            long end = System.nanoTime();
            System.out.println((end - start) / 100_000.0);
        }
    }
}

$ java ExecutorTest
6714.66053
5418.24901
5571.65213
5307.83651
5294.44132
5370.69978
5291.83493
5386.23932
5384.06842
5293.14126
5445.17405
5389.70685
^C

如你所见,平均值介于 5.3 和 5.6 微秒之间。

虽然实际时间取决于各种因素,但这两个结果之间的差异很大。使用线程池回收线程显然比创建新线程更快。