java編程中,經常會利用Executors的newXXXThreadsPool生成各種線程池,今天寫了一小段代碼,簡單測試了下三種常用的線程池:

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 測試類(因為要用到forkjoin框架,所以得繼承自RecursiveXXX)
*/
public class MathTest extends RecursiveAction {
private List<Integer> target;
private static AtomicInteger count = new AtomicInteger(0);
public MathTest(List<Integer> list) {
this.target = list;
}
public double process(Integer d) {
//模擬處理數據耗時200ms
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//System.out.println("thread:" + Thread.currentThread().getId() + "-" + Thread.currentThread().getName() + ", d: " + d);
return d;
}
@Override
protected void compute() {
if (target.size() <= 2) {
for (Integer d : target) {
process(d);
count.incrementAndGet();
}
return;
}
int mid = target.size() / 2;
MathTest t1 = new MathTest(target.subList(0, mid));
MathTest t2 = new MathTest(target.subList(mid, target.size()));
t1.fork();
t2.fork();
}
public static void main(String[] args) {
int num = 100;
int threadCount = 4;
List<Integer> target = new ArrayList<>(num);
for (int i = 0; i < num; i++) {
target.add(i);
}
MathTest test = new MathTest(target);
//原始方法,單線程跑
long start = System.currentTimeMillis();
for (int i = 0; i < target.size(); i++) {
test.process(target.get(i));
}
long end = System.currentTimeMillis();
System.out.println("原始方法耗時:" + (end - start) + "\n");
//固定線程池
final ThreadFactory fixedFactory = new ThreadFactoryBuilder().setNameFormat("fixed-%d").build();
ExecutorService service = Executors.newFixedThreadPool(threadCount, fixedFactory);
count.set(0);
start = System.currentTimeMillis();
for (Integer d : target) {
service.submit(() -> {
test.process(d);
count.incrementAndGet();
});
}
while (true) {
if (count.get() >= target.size()) {
end = System.currentTimeMillis();
System.out.println("fixedThreadPool耗時:" + (end - start) + "\n");
break;
}
}
//cached線程池
final ThreadFactory cachedFactory = new ThreadFactoryBuilder().setNameFormat("cached-%d").build();
service = Executors.newCachedThreadPool(cachedFactory);
count.set(0);
start = System.currentTimeMillis();
for (Integer d : target) {
service.submit(() -> {
test.process(d);
count.incrementAndGet();
});
}
while (true) {
if (count.get() >= target.size()) {
end = System.currentTimeMillis();
System.out.println("cachedThreadPool耗時:" + (end - start) + "\n");
break;
}
}
//newWorkStealing線程池
service = Executors.newWorkStealingPool(threadCount);
count.set(0);
start = System.currentTimeMillis();
for (Integer d : target) {
service.submit(() -> {
test.process(d);
count.incrementAndGet();
});
}
while (true) {
if (count.get() >= target.size()) {
end = System.currentTimeMillis();
System.out.println("workStealingPool耗時:" + (end - start) + "\n");
break;
}
}
//forkJoinPool
ForkJoinPool forkJoinPool = new ForkJoinPool(threadCount);
count.set(0);
start = System.currentTimeMillis();
forkJoinPool.submit(test);
while (true) {
if (count.get() >= target.size()) {
end = System.currentTimeMillis();
System.out.println("forkJoinPool耗時:" + (end - start) + "\n");
break;
}
}
}
}
代碼很簡單,就是給一個List,然后對里面的每個元素做處理(process方法),用三種線程池分別跑了一下,最后看耗時,輸出如下:
原始方法耗時:20156 fixedThreadPool耗時:5145 cachedThreadPool耗時:228 workStealingPool耗時:5047 forkJoinPool耗時:5042
環境:mac + intel i5(虛擬4核)。 workStealingPool內部其實就是ForkJoin框架,所以二者在耗時上基本一樣,符合預期;如果業務的處理時間較短,從測試結果來看,cachedThreadPool最快。
