線程池原理及其使用

線程池

線程池的優(yōu)點

  • 重復(fù)利用已經(jīng)創(chuàng)建的線程,減少創(chuàng)建線程和銷毀線程的開銷
  • 提高響應(yīng)速度,不需要等到線程創(chuàng)建就能立即執(zhí)行
  • 使用線程池可以進行統(tǒng)一分配,調(diào)優(yōu)和監(jiān)控
  • 總的來說:降低資源消耗,提高響應(yīng)速度,提高線程可管理性

線程池原理

  • 提交任務(wù)
  • 核心線程池(corePoolSize)是否已經(jīng)滿,如果未滿的話就創(chuàng)建線程執(zhí)行任務(wù)
  • 否則查看隊列(BlockingQueue)是否已滿,未滿的話,將任務(wù)存儲在隊列里
  • 如果已經(jīng)滿了,看線程池(maximumPoolSize)是否已滿,如果滿的話按照拒絕處理任務(wù)策略(handler)處理無法執(zhí)行的任務(wù)
  • 如果未滿,創(chuàng)建線程執(zhí)行任務(wù)

ThreadPoolExecutor構(gòu)造參數(shù)

  • corePoolSize:核心池的大小,構(gòu)建線程池后,并不會創(chuàng)建線程,當(dāng)前線程數(shù)如果小于corePoolSize時,當(dāng)要執(zhí)行任務(wù)時,創(chuàng)建一個線程。當(dāng)當(dāng)前線程數(shù)等于corePoolSize,會將任務(wù)放入隊列中
  • maximumPoolSize:線程池最大數(shù),也就是線程最多能創(chuàng)建的線程
  • keepAliveTime:工作線程空閑后,保持存活的時間。默認情況下,如果當(dāng)前線程數(shù)大于corePoolSize,那么一個線程如果沒有任務(wù),當(dāng)空閑的時間大于keepAliveTime時,會終止該線程,直到線程數(shù)不超過corePoolSize
  • workQueue:存儲任務(wù)的隊列,有幾種種類型隊列ArrayBlockingQueue(有界緩沖區(qū),基于數(shù)組的隊列,先進先出,必須指定大小,可以設(shè)置是否保持公平,以FIFO順序訪問),LinkedBlockingQueue(基于鏈表的隊列,如果沒有指定大小,默認為Integer.MAX_VALUE),SynchronousQueue(無界線程池,不管多少任務(wù)提交進來,直接運行)
  • ThreadFactory:線程工廠,用來創(chuàng)建線程,通過線程工廠可以給創(chuàng)建的線程設(shè)置名字
  • rejectedExecutionHandler:拒絕處理任務(wù)的策略AbortPolicy(直接放棄任務(wù),拋出RejectedExecutionException異常),DiscardPolicy(放棄任務(wù),不拋出異常),DiscardOldestPolicy(放棄最舊的未處理請求,然后重試 execute;如果執(zhí)行程序已關(guān)閉,則會丟棄該任務(wù)),CallerRunsPolicy(它直接在 execute 方法的調(diào)用線程中運行被拒絕的任務(wù);如果執(zhí)行程序已關(guān)閉,則會丟棄該任務(wù))

ThreadPoolExecutor重要方法

  • execute:在將來某個時間執(zhí)行給定任務(wù)
  • submit:提交一個任務(wù)用于執(zhí)行,并返回一個表示該任務(wù)的 Future,和execute不同的是返回的是一個Future,可以在任務(wù)執(zhí)行完畢之后得到任務(wù)執(zhí)行結(jié)果
  • shutdown:按過去執(zhí)行已提交任務(wù)的順序發(fā)起一個有序的關(guān)閉,但是不接受新任務(wù)。也就是說,中斷沒有正在執(zhí)行任務(wù)的線程,等待任務(wù)執(zhí)行完畢。
  • shutdownnow: 嘗試停止所有的活動執(zhí)行任務(wù)、暫停等待任務(wù)的處理,并返回等待執(zhí)行的任務(wù)列表。

線程池狀態(tài)

volatile int runState;
static final int RUNNING    = 0;
static final int SHUTDOWN   = 1;
static final int STOP       = 2;
static final int TERMINATED = 3;
  • RUNNING:創(chuàng)建線程池后,初始狀態(tài)為RUNNING
  • SHUTDOWN:執(zhí)行shutdown方法后,線程池處于SHUTDOWN狀態(tài)
  • STOP:執(zhí)行shutdownNow方法后,線程池處于STOP狀態(tài)
  • TERMINATED:當(dāng)線程池處于SHUTDOWN或STOP狀態(tài),并且所有工作線程已經(jīng)銷毀,任務(wù)緩存隊列已經(jīng)清空或執(zhí)行結(jié)束后,線程池被設(shè)置為TERMINATED狀態(tài)。

源碼分析

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
        if (runState == RUNNING && workQueue.offer(command)) {
            if (runState != RUNNING || poolSize == 0)
                ensureQueuedTaskHandled(command);
        }
        else if (!addIfUnderMaximumPoolSize(command))
            reject(command); // is shutdown or saturated
    }
}
  • command是否為空,是的話拋出異常
  • 如果當(dāng)前線程是否小于corePoolSize,執(zhí)行addIfUnderCorePoolSize方法,創(chuàng)建線程并執(zhí)行任務(wù)
  • 如果當(dāng)前線程線程數(shù)大于等于corePoolSize或者執(zhí)行addIfUnderCorePoolSize返回false,將當(dāng)前任務(wù)放到隊列中
  • 如果線程池狀態(tài)不是RUNNING狀態(tài)或者任務(wù)無法加入到隊列,并且線程數(shù)大于最大線程數(shù),執(zhí)行reject方法
  • 流程跟上面的線程池原理相同

配置線程池

  • cpu密集型和io密集型線程數(shù)的選擇,cpu密集型不需要太多的線程,可以充分利用cpu資源,io密集型適當(dāng)多線程,io阻塞時可以切換至另一線程。
  • 優(yōu)先級不同的的任務(wù)可以使用PriorityBlockingQueue來處理
  • 建議使用有界隊列,能夠增加系統(tǒng)的穩(wěn)定性(如果使用無界隊列,當(dāng)出現(xiàn)問題時候,隊列無限增長,此時可能會占用大量內(nèi)存,導(dǎo)致系統(tǒng)出現(xiàn)問題)和預(yù)警能力(當(dāng)出現(xiàn)隊列占滿的時候,拋出異常,可以讓開發(fā)人員及時發(fā)現(xiàn))

線程池使用

public static void main(String[] args)
    {
        
        final Vector<Integer> vector = new Vector<Integer>();
        //corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit,BlockingQueue
        ThreadPoolExecutor tp = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
        final Random random = new Random();
        System.out.println(tp.getPoolSize());
        for (int i = 0; i < 20; i++)
        {
            tp.execute(new Runnable()
            {
                public void run()
                {
                    vector.add(random.nextInt());
                    
                }
            });
        }
        
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // TODO 自動生成的 catch 塊
            e.printStackTrace();
        }
        tp.shutdown();
        System.out.println("已完成的任務(wù):"+tp.getCompletedTaskCount());
        System.out.println("活動的線程數(shù):"+tp.getActiveCount());
        System.out.println("list大?。?+vector.size());
    }
  • 上面的代碼我們自己構(gòu)建了一個ThreadPoolExecutor,而Executor給我們提供了幾個靜態(tài)方法用于創(chuàng)建線程池,本質(zhì)上只是設(shè)置了給定的參數(shù)而已
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
  • FixedThreadPool,顧名思義,一個固定大小的線程池,隊列使用的無限制大小的鏈表阻塞隊列
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
  • 單線程線程池,同樣隊列使用的無限制大小的鏈表阻塞隊列
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
  • 無界線程池,無論多少任務(wù),直接運行,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程

我覺得分享是一種精神,分享是我的樂趣所在,不是說我覺得我講得一定是對的,我講得可能很多是不對的,但是我希望我講的東西是我人生的體驗和思考,是給很多人反思,也許給你一秒鐘、半秒鐘,哪怕說一句話有點道理,引發(fā)自己內(nèi)心的感觸,這就是我最大的價值。(這是我喜歡的一句話,也是我寫博客的初衷)

作者:jiajun 出處: http://www.cnblogs.com/-new/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容