線程池的基本使用

線程池作用

借由《Java并發(fā)編程的藝術(shù)》

  • 降低資源消耗。通過重復(fù)利用已經(jīng)創(chuàng)建的線程,能夠降低線程創(chuàng)建和銷毀造成的消耗。
  • 提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時,任務(wù)可以不需要等待線程的創(chuàng)建就能立即執(zhí)行。
  • 提高線程的可管理性。線程是稀缺資源,如果無限制地創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,使用線程池可以進(jìn)行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。

ThreadPoolExecutor類

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    ...
}

ThreadPoolExecutor構(gòu)造

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

  • corePoolSize:核心線程數(shù)量,初始化就創(chuàng)建的線程,沒有任務(wù)也不會被關(guān)閉的線程。也會有例外,如:allowCoreThreadTimeOut設(shè)置為true時,會被關(guān)閉。
  • maximumPoolSize:最大線程數(shù)量。
  • keepAliveTime:空閑線程的存活時間,超時后線程會被關(guān)閉,核心線程除外。
  • unit:空閑時間單位,一般使用TimeUnit枚舉
  • workQueue:工作隊列,當(dāng)所有線程都被占用后,新的任務(wù)就會被放在工作隊列中。
  • threadFactory:線程工廠。
  • handler:飽和策略,用于線程池中沒有空閑線程可以使用且工作列也處于飽和狀態(tài)時執(zhí)行的拒絕策略。

常用的拒絕策略

  • AbortPolicy:拋出RejectedExecutionException異常拒絕新的任務(wù)處理,默認(rèn)拒絕策略。
  • CallerRunsPolicy:如果程序關(guān)閉,會丟掉任務(wù)。此策略提供簡單的反饋控制機(jī)制,能夠減緩新任務(wù)的提交速度,但會造成延遲。如果項目可以承受延遲且不能丟棄任何一個任務(wù)請求,可以使用此策略。
  • DiscardPolicy:不處理新任務(wù),直接丟掉。
  • DiscardOldestPolicy:丟失最早的未處理的任務(wù)。

ThreadPoolExecutor線程狀態(tài)

  • RUNNING:接收新的任務(wù)和處理隊列中的任務(wù)
  • SHUTDOWN:不能新增任務(wù),但是會繼續(xù)處理已經(jīng)添加的任務(wù)
  • STOP:不能新增任務(wù),不會繼續(xù)處理已經(jīng)添加任務(wù)
  • TIDYING:所有的任務(wù)已經(jīng)被終止,工作線程為0
  • TERMINATED:terminated()方法執(zhí)行完成

創(chuàng)建線程池

創(chuàng)建Runnable接口實現(xiàn)類

public class MyThread implements Runnable {

    private String taskName;

    public MyThread(String taskName) {
        this.taskName = taskName;
    }

    @Override
    public void run() {
        try {
            String threadName = Thread.currentThread().getName();
            System.out.println("線程 " + threadName + " 開始執(zhí)行:" + taskName);
            Thread.sleep(3000);
            System.out.println("線程 " + threadName + " 開始執(zhí)行:" + taskName);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String toString() {
        return "MyThread{" +
                "taskName='" + taskName + '\'' +
                '}';
    }
}

使用ThreadPoolExecutor創(chuàng)建

public static void main(String[] args) {

    ThreadPoolExecutor executor = new ThreadPoolExecutor(
            // 核心線程數(shù)
            5,
            // 最大線程數(shù)
            10,
            // 等待時間
            100,
            // 等待時間單位  秒
            TimeUnit.SECONDS,
            // 任務(wù)隊列 容量100
            new ArrayBlockingQueue<>(100),
            // 飽和策略
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    for (int i = 1; i <= 10; i++) {
        MyThread myThread = new MyThread("任務(wù)" + i);
        executor.execute(myThread);
    }

    executor.shutdown();
}

幾種常見的線程池

固定線程池(FixThreadPool)

線程池中的固定數(shù)量線程可以重復(fù)使用

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  threadFactory);
}

創(chuàng)建方法:

ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 1; i <= 10; i++) {
    MyThread myThread = new MyThread("任務(wù)" + i);
    executor.execute(myThread);
}
  • 當(dāng)前運(yùn)行的線程數(shù)小于coreSize的時候,有新任務(wù)就創(chuàng)建線程來執(zhí)行。
  • 當(dāng)前運(yùn)行的線程數(shù)等于coreSize的時候,有新任務(wù)將會追加到LinkedBlockingQueue隊列中。
  • 線程池中的線程執(zhí)行完后,會循環(huán)從LinkedBlockingQueue中獲取任務(wù)執(zhí)行。

需要注意的是,LinkedBlockingQueue是一個無界隊列,它的容量為:Integer.MAX_VALUE,也就是說,當(dāng)所有線程被占用后,新的任務(wù)將會無限堆加到這個隊列中,如果任務(wù)較多,可能會出現(xiàn)OOM現(xiàn)象。

單一線程池(SingleThreadExecutor)

只有一個線程,空閑也不會被關(guān)閉。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

創(chuàng)建方法:

ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 1; i <= 10; i++) {
    MyThread myThread = new MyThread("任務(wù)" + i);
    executor.execute(myThread);
}

緩存線程池(CachedThreadPool)

線程數(shù)量為Integer.MAX_VALUE,空閑線程會被臨時緩存60s,沒有任務(wù)分配會關(guān)閉。如果提交任務(wù)速度過快,也一樣可能會出現(xiàn)OOM現(xiàn)象。

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

創(chuàng)建方法:

ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 1; i <= 10; i++) {
    MyThread myThread = new MyThread("任務(wù)" + i);
    executor.execute(myThread);
}

原文發(fā)布在:傳送門

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

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