線程池的有點:省時、省資源、更好管理線程
1、減少資源的消耗:較少線程創建和銷燬造成的消耗
2、提高響應速度:當任務到達的時候,就能夠立刻執行,減少了線程創建和銷燬的時間
3、能夠更好地管理線程
ThreadPoolExecutor 的類關係
Executor:接口,是線程池的基礎,將任務的提交與任務的執行分離開來。
ExecutorService:接口:繼承了Executor,新加了shutdown(),submit()
AbstractExecutorService:實現了ExecutorService大部分方法,可以少寫很多代碼
ThreadPoolExecutor:線程池的核心實現了,用來執行被提交的任務
ScheduledExecutorService:提供了帶週期執行的ExecutorService
ScheduledThreadPoolExecutor:可以延遲執行任務
線程池的創建各個參數含義
完整的構造函數
public ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize
線程池中的核心線程數,當提交一個任務時,線程池創建一個新線程執行任務,直到線程數=corePoolSize,之後提交的任務會被保存到阻塞隊列中,等待被執行。
備註:如果執行了線程池的prestartAllCoreThreads()方法,線程池會提前創建好corePoolSize數量的線程,提高效率
maximumPoolSize
如果線程數=corePoolSize,且阻塞隊列也被塞滿了,這個時候再提交任務,就會再創建線程執行任務,但是線程池總線程數必須<=maximumPoolSize
keepAliveTime
當線程數>corePoolSize時,當前線程沒有任務執行,線程繼續存活的時間
線程空閒時的存活時間,即當線程沒有任務執行時,繼續存活的時間。默認情況下,該參數只在線程數大於corePoolSize時纔有用
TimeUnit
keepAliveTime線程存活的時間單位
關於小時的常用方法
TimeUnit.HOURS.toMillis(1) | 1小時轉分 |
TimeUnit.HOURS.toMinutes(60) | 60小時轉分 |
TimeUnit.HOURS.sleep(5) | 線程休眠5秒 |
TimeUnit.HOURS.convert(1, TimeUnit.MINUTES) | 1小時轉秒 |
常用工具類
TimeUnit.DAYS | 日的工具類 |
TimeUnit.HOURS | 時的工具類 |
TimeUnit.MINUTES | 分的工具類 |
TimeUnit.SECONDS | 秒的工具類 |
TimeUnit.MILLISECONDS | 毫秒的工具類 |
workQueue
workQueue必須是BlockingQueue阻塞隊列:當線程池的線程數超過corePoolSize的時候,多餘的線程就會進入阻塞隊列中,等待被執行
應當儘量使用有界阻塞隊列,比如:LinkedBlockingQueue、ArrayBlokngQueue、SynchronousQueue、PriorityBlockingQueue,使用無界阻塞隊列(比如:DelayQueue、LinkedtransferQueue)會產生如下影響
1、當線程數超過corePoolSize之後,其他線程就會放在無界隊列中等待,就不會再創建新的線程來執行任務了,導致界隊列時maximumPoolSize將是一個無效參數。
2、由於1,使用無界隊列的keepAliveTime參數無效
3、無界隊列可能會耗盡系統資源
threadFactory
創建線程的工廠,使用場景
1、通過自定義的線程工廠,給每個新建的線程設置一個有識別度的線程名
2、通過線程工廠把所有的線程設置爲守護線程
demo
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10,
20,
20,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
//1、設置線程的名字
Thread thread = new Thread(r);
//thread.setName("通過自定義線程工廠誰知線程名字");
//2、設置成守護線程
//thread.setDaemon(true);
return thread;
}
},
// new ThreadPoolExecutor.CallerRunsPolicy());
// new ThreadPoolExecutor.DiscardOldestPolicy());
// new ThreadPoolExecutor.DiscardPolicy());
new AbortPolicy());
}
}
RejectedExecutionHandler
當阻塞隊列被塞滿了,並且沒有多餘的線程執行任務的時候,對於新添加進來的任務必須做一個處理
AbortPolicy | 默認:直接拋異常 |
CallerRunsPolicy | 用調用者線程來執行(比如main) |
DiscardOldestPolicy | 丟掉隊列中最靠前的任務,並執行當前任務 |
DiscardPolicy | 直接丟掉任務 |
實現RejectedExecutionHandler | 日誌記錄或者持久化存儲 |
demo
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10,
20,
20,
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(10), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
//1、設置線程的名字
Thread thread = new Thread(r);
//thread.setName("通過自定義線程工廠誰知線程名字");
//2、設置成守護線程
//thread.setDaemon(true);
return thread;
}
},
// new ThreadPoolExecutor.CallerRunsPolicy());
// new ThreadPoolExecutor.DiscardOldestPolicy());
// new ThreadPoolExecutor.DiscardPolicy());
new AbortPolicy());
}
}