Java併發編程之ThreadPool線程池基礎部分-----什麼是線程池,線程池架構,怎麼使用

一.爲什麼要用線程池

線程池是一種多線程處理形式。

線程池做的工作只要是控制運行的線程數量,處理過程中將任務放入隊列,然後在線程創建後啓動這些任務,如果線程數量超過了最大數量,超出數量的線程排隊等候,等其他線程執行完畢,再從隊列中取出任務來執行


線程池的主要特點爲: 線程複用;控制最大併發數;管理線程

  1. 降低資源消耗。通過重複利用已創建的線程降低線程創建和銷燬造成的銷耗
  2. 提高響應速度。當任務到達時,任務可以不需要等待線程創建就能立即執行
  3. 提高線程的可管理性。線程是稀缺資源,如果無限制的創建,不僅會銷耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一的分配,調優和監控

二.JDK1.8線程池架構

Java中的線程池是通過Executor框架實現的,該框架中用到了Executor,Executors,ExecutorService,ThreadPoolExecutor這幾個類

Executor:

public interface Executor {
    void execute(Runnable command);
}

Executor的官方定義是An object that executes submitted {@link Runnable} tasks 翻譯過來就是:執行提交的任務(Runnable形式)


ExecutorService:

ExecutorService是Executor的子接口,它是Executor的擴展,能提供管理終止的方法(shutdown),以及可以生成Future對象以跟蹤一個或多個異步任務的進度的方法
在這裏插入圖片描述

ThreadPoolExecutor:

ThreadPoolExecutor是線程池類,它提供幾種構造函數讓我們來創建線程池。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

線程池的參數非常重要,之後會有文章講。


Executors:

Executors 工具類提供了四種不同的線程池來幫助我們創建不同需求的線程池,其實質也是調用ThreadPoolExecutor的構造方法。


三.代碼示例:三種線程池

應用場景:銀行有n個櫃檯,有10個顧客辦理業務


public static void main(String[] args) {

        //1.newFixedThreadPool 固定個數線程池
        //ExecutorService threadPool = Executors.newFixedThreadPool(5);

        //2.newSingleThreadExecutor 一池一線程
        //ExecutorService threadPool = Executors.newSingleThreadExecutor();

        //3.newCachedThreadPool 可擴容 有伸縮性 遇強則強
        //ExecutorService threadPool = Executors.newCachedThreadPool();

        try {

            for (int i = 1; i <= 10 ; i++) { //模擬10個顧客,execute傳入參數是Runnable函數式接口

                threadPool.execute(()->{

                    System.out.println(Thread.currentThread().getName()+"\t辦理業務");

                }); 

                //暫停400ms
                try { TimeUnit.MILLISECONDS.sleep(400); }catch (Exception e){ e.printStackTrace(); }

            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            threadPool.shutdown();
        }


    }

首先我們創建線程池,這裏用的是Executors提供的方法,其次我們用循環模擬10個任務,讓線程池的線程來執行,最後在finally語句塊調用shutdown關閉


1.Executors.newFixedThreadPool(int n)

執行長期任務性能好,創建一個線程池,一池有N個固定的線程,有固定線程數的線程。可以通過將第一個語句註釋去掉運行看看結果:

pool-1-thread-1	辦理業務
pool-1-thread-2	辦理業務
pool-1-thread-3	辦理業務
pool-1-thread-4	辦理業務
pool-1-thread-5	辦理業務
pool-1-thread-1	辦理業務
pool-1-thread-2	辦理業務
pool-1-thread-3	辦理業務
pool-1-thread-4	辦理業務
pool-1-thread-5	辦理業務

Process finished with exit code 0

發現首先滿足了我們的需求,其次分佈很均勻,這是因爲我們用TimeUnit睡了一段時間,否則就會比較混亂。


2.newSingleThreadExecutor

一個任務一個任務的執行,一池一線程 這相當於只有一個櫃檯能辦理業務

"C:\Program Files\Java\jdk1.8.0_181\bin\java.exe" "-javaagent:D:\idea\IntelliJ IDEA 2019.2.3\lib\idea_rt.jar=55234:D:\idea\IntelliJ IDEA 2019.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_181\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_181\jre\lib\rt.jar;C:\Users\李肇京\IdeaProjects\JUC\out\production\JUC" JUC_01_SellTicket.ExecutorDemo.MyThreadPoolDemo
pool-1-thread-1	辦理業務
pool-1-thread-1	辦理業務
pool-1-thread-1	辦理業務
pool-1-thread-1	辦理業務
pool-1-thread-1	辦理業務
pool-1-thread-1	辦理業務

3.newCachedThreadPool

執行很多短期異步任務,線程池根據需要創建新線程,但在先前構建的線程可用時將重用它們。可擴容,遇強則強

  • 此時,如果我們把暫停線程的語句加上,你會發現情況跟2一樣了,一直是一個線程來處理我們的任務,這是因爲線程池認爲當前情況下不需要多個線程處理
  • 如果把暫停語句去掉,或者把任務數增大,線程池會自動擴容,這時就會有多個線程處理我們的任務。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章