以前寫了一篇文章關於四種線程池的解析。 可是對於FixedThreadPool與CachedThreadPool適用的場景其實仍是比較模糊難以界定的。因此筆者今天經過設計大任務併發和小任務併發來驗證FixedThreadPool與CachedThreadPool的適用場景。html
首先我設計了一個任務基類,它經過計算圓周率來模擬cpu的密集計算、經過寫日誌到本地文件來模擬IO。 這兩個方法都經過參數n來調整任務的大小規模。bash
public class Task {
/**
* 經過計算圓周率模擬cpu計算
* 經過公式 π=4*(1-1/3+1/5-1/7+1/9-1/11+....)
*
* @return
*/
public static double calculatePI(long n) {
double item = 0.0;
double sum = 0;
int flag = -1;
for (int i = 0; i <= n; i++) {
flag *= -1;
item = flag * 1.0 / (2 * i + 1);
sum += item;
}
return sum * 4;
}
/**
* 經過寫日誌模擬IO操做
* @param n
*/
public static void writeIO(int n) {
try {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS");
String fileName = Thread.currentThread().getName() + "-" + format.format(date) + ".log";
FileOutputStream os = new FileOutputStream("C:\\Users\\valarchie\\Desktop\\logs\\" + fileName);
for (int i = 0; i < n; i++) {
os.write(("寫入日誌" + i + "次").getBytes());
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
複製代碼
在筆者的設計當中大任務的規模是小任務的10倍,具體請看代碼:多線程
大任務:併發
public class BigTask extends Task implements Runnable {
private CountDownLatch latch;
public BigTask(CountDownLatch latch) {
this.latch = latch;
}
public static double calculatePI() {
return calculatePI(100000000);
}
public static void writeIO() {
writeIO(100);
}
@Override
public void run() {
calculatePI();
writeIO();
latch.countDown();
}
}
複製代碼
小任務:ide
public class SmallTask extends Task implements Runnable {
private CountDownLatch latch;
public SmallTask(CountDownLatch latch) {
this.latch = latch;
}
public static double calculatePI() {
return calculatePI(10000000);
}
public static void writeIO() {
writeIO(10);
}
@Override
public void run() {
calculatePI();
writeIO();
latch.countDown();
}
}
複製代碼
經過測試咱們得出一個小任務的運行時間大概在86ms左右。一個大任務的運行時間大概在575ms左右。 接下來咱們分別測試100個大任務和100個小任務分別在單線程、FixedThreadPool、CachedThreadPool三種狀況下的運行時間(個人筆記本是4核的,通過簡單測試FixedThreadPool在16線程數的狀況下性能最優良)。性能
咱們使用CountDownLatch的計算多線程的運行時間,如下是多線程的測試代碼模板:測試
public static void main(String[] args) {
int taskCount = 100;
CountDownLatch latch = new CountDownLatch(taskCount);
ExecutorService executorService = Executors.newFixedThreadPool(16);
long t1 = System.currentTimeMillis();
for (int i = 0; i < taskCount; i++) {
executorService.submit(new SmallTask(latch));
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long t2 = System.currentTimeMillis();
// 得出多線程的運行時間
System.out.println(t2 - t1);
executorService.shutdown();
}
複製代碼
任務模型*100 | 單線程 | FixedThreadPool | CachedThreadPool |
---|---|---|---|
大任務 | 45067ms | 6613ms | 6224ms |
小任務 | 4754ms | 722ms | 726ms |
經過統計發現多線程的性能比單線程的性能優異不少,可是其實FixedThreadPool和CachedThreadPool的性能差別是差很少相等的並無比較大差異。ui
爲了更嚴謹一點,咱們控制任務方法的規模和任務數量的規模再進行一次測試this
任務模型*100 | FixedThreadPool | CachedThreadPool |
---|---|---|
大任務方法規模*10 | 78738ms | 79669ms |
大任務數量規模*10 | 73654ms | 69343ms |
筆者通過驗證得出的結論是兩種線程池其實在性能上沒有很是大差異,可是FixedThreadPool能夠控制線程的併發數量,而CachedThreadPool不能控制線程的併發數量。若是線程數量爆發增加的話對系統會帶來危害。我的認爲使用FixedThreadPool會更好。spa