6.1 線程池的優點、以及各個參數的意義、使用示例

線程池的有點:省時、省資源、更好管理線程 

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());

    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章