一、幾種常用線程池
1、newCachedThreadPool
創(chuàng)建一個可緩存線程池秸歧,如果線程池長度超過處理需要恬涧,可靈活回收空閑線程,若無可回收胎挎,則新建線程。
這種類型的線程池特點是:
- 工作線程的創(chuàng)建數量幾乎沒有限制(其實也有限制的,數目為Interger. MAX_VALUE), 這樣可靈活的往線程池中添加線程。
- 如果長時間沒有往線程池中提交任務谆趾,即如果工作線程空閑了指定的時間(默認為1分鐘),則該工作線程將自動終止叛本。終止后沪蓬,如果你又提交了新的任務,則線程池重新創(chuàng)建一個工作線程来候。
- 在使用CachedThreadPool時跷叉,一定要注意控制任務的數量,否則营搅,由于大量線程同時運行云挟,很有會造成系統(tǒng)癱瘓。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
final int index = i;
try {
Thread.sleep(index * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cachedThreadPool.execute(new Runnable() {
public void run() {
System.out.println(index);
}
});
}
}
}
2转质、newFixedThreadPool
- 創(chuàng)建一個指定工作線程數量的線程池园欣。每當提交一個任務就創(chuàng)建一個工作線程,如果工作線程數量達到線程池初始的最大數休蟹,則將提交的任務存入到池隊列中沸枯。
- FixedThreadPool是一個典型且優(yōu)秀的線程池日矫,它具有線程池提高程序效率和節(jié)省創(chuàng)建線程時所耗的開銷的優(yōu)點。但是辉饱,在線程池空閑時搬男,即線程池中沒有可運行任務時,它不會釋放工作線程彭沼,還會占用一定的系統(tǒng)資源缔逛。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
final int index = i;
fixedThreadPool.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
3、newSingleThreadExecutor
- 創(chuàng)建一個單線程化的Executor姓惑,即只創(chuàng)建唯一的工作者線程來執(zhí)行任務褐奴,它只會用唯一的工作線程來執(zhí)行任務,保證所有任務按照指定順序(FIFO, LIFO, 優(yōu)先級)執(zhí)行于毙。如果這個線程異常結束敦冬,會有另一個取代它,保證順序執(zhí)行唯沮。單工作線程最大的特點是可保證順序地執(zhí)行各個任務脖旱,并且在任意給定的時間不會有多個線程是活動的。
package test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() {
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
4介蛉、newScheduleThreadPool
- 創(chuàng)建一個定長的線程池萌庆,而且支持定時的以及周期性的任務執(zhí)行,支持定時及周期性任務執(zhí)行币旧。
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
// 延遲3秒執(zhí)行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() {
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
}
}
package test;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
public static void main(String[] args) {
// 表示延遲1秒后每3秒執(zhí)行一次
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
}
}
二践险、線程池參數配置選擇(CPU數量可以用Runtime.availableProcessors方法獲取)
- 高并發(fā)吹菱、任務執(zhí)行時間短的線程要盡量減少線程上下文的切換巍虫,可以設置線程池數CPU+1個線程。
- 并發(fā)不高鳍刷、任務執(zhí)行時間長的業(yè)務占遥,分為兩種:
- 一種是IO密集型,時間主要集中在IO上输瓜,因為IO操作不占用CPU瓦胎,所以盡量不讓CPU閑下來,可以多設置線程數前痘,可以設置 = CPU數量 * CPU利用率 * (1 + 線程等待時間/線程CPU時間)
- 第二種業(yè)務時間主要集中在計算操作中凛捏,計算密集型,也要盡量減少線程上下文的切換芹缔,線程數要設置的少一些
- 并發(fā)高坯癣,業(yè)務執(zhí)行時間也長的業(yè)務要看具體的情況,首先要看架構的設計是否還能有優(yōu)化的余地比如緩存什么最欠,減少并發(fā)示罗,或者增加機器等惩猫,業(yè)務執(zhí)行時間長看是否可以拆分成小任務執(zhí)行,線程數的設置參考第二種情況
三蚜点、linux查看服務器CPU數量
首先明白兩個概念轧房,物理CPU和邏輯CPU。
- 物理CPU:服務器上實際安裝的CPU绍绘。一個物理CPU可以有多個核奶镶。
- 邏輯CPU:數量 = 物理CPU數量 x CPU核數。如果開啟了HT陪拘,再 x 2厂镇。
- 想要知道服務器的邏輯CPU個數,使用命令: cat /proc/cpuinfo | grep 'processor' | wc -l
- 想要知道服務器的物理CPU個數左刽,使用命令: cat /proc/cpuinfo | grep 'physical id' | sort | uniq | wc -l