陷阱 - 執行緒建立相對昂貴

考慮這兩個微基準:

第一個基準測試只是建立,啟動和連線執行緒。執行緒的 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 微秒之間。

雖然實際時間取決於各種因素,但這兩個結果之間的差異很大。使用執行緒池回收執行緒顯然比建立新執行緒更快。