您的 CPU 以 100% 运行这一事实并不能说明他们在做有用的工作有多忙。在您的情况下,您使用的线程多于内核,因此 100% 包含一些上下文切换并不必要地使用内存(对 100 个线程的影响很小),这是次优的。
对于 CPU 密集型任务,我通常使用这个成语:
private final int NUM_THREADS = Runtime.getRuntime().availableProcessors() + 1;
private final ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
正如其他人所指出的,使用更多线程只会引入不必要的上下文切换。
显然,如果任务执行一些 I/O 和其他阻塞操作,这是不适用的,更大的池是有意义的。
编辑
为了回复@MartinJames 评论,我运行了一个(简单的)基准测试——结果表明,从池大小 = 处理器数量 + 1 到 100 只会稍微降低性能(我们称之为 5%)——更高的数字( 1000 和 10000)确实显着影响了性能。
结果是 10 次运行的平均值:
池大小:9:238 毫秒。//(NUM_CORES+1)
池大小:100:245 毫秒。
池大小:1000:319 毫秒。
池大小:10000:2482 毫秒。
代码:
public class Test {
private final static int NUM_CORES = Runtime.getRuntime().availableProcessors();
private static long count;
private static Runnable r = new Runnable() {
@Override
public void run() {
int count = 0;
for (int i = 0; i < 100_000; i++) {
count += i;
}
Test.count += count;
}
};
public static void main(String[] args) throws Exception {
//warmup
runWith(10);
//test
runWith(NUM_CORES + 1);
runWith(100);
runWith(1000);
runWith(10000);
}
private static void runWith(int poolSize) throws InterruptedException {
long average = 0;
for (int run = 0; run < 10; run++) { //run 10 times and take the average
Test.count = 0;
ExecutorService executor = Executors.newFixedThreadPool(poolSize);
long start = System.nanoTime();
for (int i = 0; i < 50000; i++) {
executor.submit(r);
}
executor.shutdown();
executor.awaitTermination(10, TimeUnit.SECONDS);
long end = System.nanoTime();
average += ((end - start) / 1000000);
System.gc();
}
System.out.println("Pool size: " + poolSize + ": " + average / 10 + " ms. ");
}
}