Java線程池

來源:互聯網
上載者:User

標籤:executors   odi   封裝   abort   無限   意思   最大值   儲存   大於   

一.為什麼要用線程池1.減少了建立和銷毀線程的次數,每個背景工作執行緒都可以被重複利用,可執行多個任務。2.可以根據系統的承受能力,調整線程池中工作線線程的數目,防止因為消耗過多的記憶體,而把伺服器累趴下(每個線程需要大約1MB記憶體,線程開的越多,消耗的記憶體也就越大,最後死機)。Java裡麵線程池的頂級介面是Executor,但是嚴格意義上講Executor並不是一個線程池,而只是一個執行線程的工具。真正的線程池介面是ExecutorService。 二.比較幾個重要的類ExecutorService : 真正的線程池介面。ScheduledExecutorService :  能和Timer/TimerTask類似,解決那些需要任務重複執行的問題。ThreadPoolExecutor : ExecutorService的預設實現。ScheduledThreadPoolExecutor : 繼承ThreadPoolExecutor的ScheduledExecutorService介面實現,週期性任務調度的類實現。 1. 繼承關係:    ThreadPoolExexutor繼承了AbstractExecutorService    AbstractExecutorService實現了ExecutorService    ExecutorService繼承了Executor 2. ThreadPoolExecutor、AbstractExecutorService、ExecutorService和Executor幾個之間的關係:    Executor是一個頂層介面,在它裡面只聲明了一個方法execute(Runnable),傳回值為void,參數為Runnable類型,從字面意思可以理解,就是用來執行傳進去的任務的;    然後ExecutorService介面繼承了Executor介面,並聲明了一些方法:submit、invokeAll、invokeAny以及shutDown等;    抽象類別AbstractExecutorService實現了ExecutorService介面,基本實現了ExecutorService中聲明的所有方法;    然後ThreadPoolExecutor繼承了類AbstractExecutorService。  3. ThreadPoolExecutor類中提供的四種構造方法:public class ThreadPoolExecutor extends AbstractExecutorService {    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,            BlockingQueue<Runnable> workQueue);    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,            BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,            BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);    public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,        BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);}  4. 各個參數的含義: corePoolSize:核心池的大小,這個參數跟後面講述的線程池的實現原理有非常大的關係。在建立了線程池後,預設情況下,線程池中並沒有任何線程,而是等待有任務到來才建立線程去執行任務,除非調用了prestartAllCoreThreads()或者prestartCoreThread()方法,  從這2個方法的名字就可以看出,是預建立線程的意思,即在沒有任務到來之前就建立corePoolSize個線程或者一個線程。預設情況下,在建立了線程池後,線程池中的線程數為0,當有任務來之後,就會建立一個線程去執行任務,當線程池中的線程數目達到corePoolSize後,就會把到達的任務放到緩衝隊列當中;  maximumPoolSize:線程池最大線程數,這個參數也是一個非常重要的參數,它表示線上程池中最多能建立多少個線程  keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止。預設情況下,只有當線程池中的線程數大於corePoolSize時,keepAliveTime才會起作用,直到線程池中的線程數不大於corePoolSize,即當線程池中的線程數大於corePoolSize時,  如果一個線程閒置時間達到keepAliveTime,則會終止,直到線程池中的線程數不超過corePoolSize。但是如果調用了allowCoreThreadTimeOut(boolean)方法,線上程池中的線程數不大於corePoolSize時,keepAliveTime參數也會起作用,直到線程池中的線程數為0;  unit:參數keepAliveTime的時間單位,有7種取值,在TimeUnit類中有7種靜態屬性:    TimeUnit.DAYS;               //天    TimeUnit.HOURS;             //小時    TimeUnit.MINUTES;           //分鐘    TimeUnit.SECONDS;           //秒    TimeUnit.MILLISECONDS;      //毫秒    TimeUnit.MICROSECONDS;      //微妙    TimeUnit.NANOSECONDS;       //納秒  workQueue:一個阻塞隊列,用來儲存等待執行的任務,這個參數的選擇也很重要,會對線程池的運行過程產生重大影響,一般來說,這裡的阻塞隊列有以下幾種選擇      ArrayBlockingQueue:基於數組結構的有界阻塞隊列,按FIFO排序任務;      LinkedBlockingQuene:基於鏈表結構的阻塞隊列,按FIFO排序任務,輸送量通常要高於      SynchronousQuene:一個不儲存元素的阻塞隊列,每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,輸送量通常要高於ArrayBlockingQuene;      PriorityBlockingQuene:具有優先順序的無界阻塞隊列;  threadFactory:線程工廠,主要用來建立線程;  handler:表示當拒絕處理任務時的策略,有以下四種取值:    ThreadPoolExecutor.AbortPolicy:丟棄任務並拋出RejectedExecutionException異常。    ThreadPoolExecutor.DiscardPolicy:也是丟棄任務,但是不拋出異常。    ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然後重新嘗試執行任務(重複此過程)    ThreadPoolExecutor.CallerRunsPolicy:由調用線程處理該任務 三.Java內建的四種線程池 newSingleThreadExecutor: 建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那麼線程池會補充一個新線程。 newFixedThreadPool: 建立固定大小的線程池。每次提交一個任務就建立一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執行異常而結束,那麼線程池會補充一個新線程。 newCachedThreadPool: 建立一個可快取的線程池。如果線程池的大小超過了處理任務所需要的線程,那麼就會回收部分空閑(60秒不執行任務)的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。此線程池不會對線程池大小做限制,線程池大小完全依賴於作業系統(或者說JVM)能夠建立的最大線程大小。 newScheduledThreadPool: 建立一個大小無限的線程池。此線程池支援定時以及周期性執行任務的需求 四.線程池的組成部分1.線程池管理器: 建立、銷毀並管理線程池,將背景工作執行緒放入線程池中2.背景工作執行緒: 一個可以迴圈執行任務的線程,在沒有任務時將進行等待3.任務列隊: 提供一種緩衝機制,將沒有處理的任務放在任務隊列中4.任務介面: 是每個任務必須實現的介面,主要用來規定任務的入口、任務執行完後的收尾工作、任務的執行狀態等,背景工作執行緒通過該介面調度任務的執行 五.PoolSize線程池中的核心線程數,當提交一個任務時,線程池建立一個新線程執行任務,直到當前線程數等於corePoolSize;如果當前線程數為corePoolSize,繼續提交的任務被儲存到阻塞隊列中,等待被執行;如果阻塞隊列滿了,那就建立新的線程執行當前任務;直到線程池中的線程數達到maxPoolSize,這時再有任務來,只能執行reject()處理該任務; 六.線程池的狀態(5種)  1、RUNNING:-1 << COUNT_BITS,即高3位為111,該狀態的線程池會接收新任務,並處理阻塞隊列中的任務;  2、SHUTDOWN: 0 << COUNT_BITS,即高3位為000,該狀態的線程池不會接收新任務,但會處理阻塞隊列中的任務;  3、STOP : 1 << COUNT_BITS,即高3位為001,該狀態的線程不會接收新任務,也不會處理阻塞隊列中的任務,而且會中斷正在啟動並執行任務;  4、TIDYING : 2 << COUNT_BITS,即高3位為010,該狀態表示線程池對線程進行整理最佳化;  5、TERMINATED: 3 << COUNT_BITS,即高3位為011,該狀態表示線程池停止工作; 七.向線程池提交任務 execute()內部實現1.首次通過workCountof()獲知當前線程池中的線程數,  如果小於corePoolSize, 就通過addWorker()建立線程並執行該任務; 否則,將該任務放入阻塞隊列;2. 如果能成功將任務放入阻塞隊列中,  如果當前線程池是非RUNNING狀態,則將該任務從阻塞隊列中移除,然後執行reject()處理該任務;  如果當前線程池處於RUNNING狀態,則需要再次檢查線程池(因為可能在上次檢查後,有線程資源被釋放),是否有閒置線程;如果有則執行該任務;3、如果不能將任務放入阻塞隊列中,說明阻塞隊列已滿;那麼將通過addWoker()嘗試建立一個新的線程去執行這個任務;如果addWoker()執行失敗,說明線程池中線程數達到maxPoolSize,則執行reject()處理任務;  sumbit()內部實現會將提交的Callable任務會被封裝成了一個FutureTask對象FutureTask類實現了Runnable介面,這樣就可以通過Executor.execute()提交FutureTask到線程池中等待被執行,最終執行的是FutureTask的run方法;比較:兩個方法都可以向線程池提交任務,execute()方法的傳回型別是void,它定義在Executor介面中, 而submit()方法可以返回持有計算結果的Future對象,它定義在ExecutorService介面中,它擴充了Executor介面,其它線程池類像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有這些方法。  總結executor() vs submit():(1)execute()方法實際上是Executor中聲明的方法,在ThreadPoolExecutor進行了具體的實現,這個方法是ThreadPoolExecutor的核心方法,通過這個方法可以向線程池提交一個任務,交由線程池去執行。(2)submit()方法是在ExecutorService中聲明的方法,在AbstractExecutorService就已經有了具體的實現,在ThreadPoolExecutor中並沒有對其進行重寫,這個方法也是用來向線程池提交任務的,但是它和execute()方法不同,它能夠返回任務執行的結果,去看submit()方法的實現,會發現它實際上還是調用的execute()方法,只不過它利用了Future來擷取任務執行結果。 八.線程池的關閉ThreadPoolExecutor提供了兩個方法,用於線程池的關閉,分別是shutdown()和shutdownNow(),其中:   shutdown():不會立即終止線程池,而是要等所有任務緩衝隊列中的任務都執行完後才終止,但再也不會接受新的任務   shutdownNow():立即終止線程池,並嘗試打斷正在執行的任務,並且清空任務緩衝隊列,返回尚未執行的任務  九.實現
import org.junit.Test;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class TestExecutor {    @Test    public void testSingleThreadExecutorPool() {        ExecutorService pool = Executors.newSingleThreadExecutor();        Thread t1 = new MyThread();        Thread t2 = new MyThread();        Thread t3 = new MyThread();        Thread t4 = new MyThread();        Thread t5 = new MyThread();        pool.execute(t1);        pool.execute(t2);        pool.execute(t3);        pool.execute(t4);        pool.execute(t5);        pool.shutdown();        /*         pool-1-thread-1正在執行...         pool-1-thread-1正在執行...         pool-1-thread-1正在執行...         pool-1-thread-1正在執行...         pool-1-thread-1正在執行...         */    }    @Test    public void testFixThreadExecutorPool() {        //建立一個可重用固定線程數的線程池        ExecutorService pool = Executors.newFixedThreadPool(2);        //建立實現了Runnable介面對象,Thread對象當然也實現了Runnable介面        Thread t1 = new MyThread();        Thread t2 = new MyThread();        Thread t3 = new MyThread();        Thread t4 = new MyThread();        Thread t5 = new MyThread();        //將線程放入池中進行執行        pool.execute(t1);        pool.execute(t2);        pool.execute(t3);        pool.execute(t4);        pool.execute(t5);        //關閉線程池        pool.shutdown();        /*         *pool-1-thread-1正在執行...         *pool-1-thread-2正在執行...         *pool-1-thread-1正在執行...         *pool-1-thread-2正在執行...         *pool-1-thread-1正在執行...         */    }    @Test    public void testCachedThreadExecutorPool() {        //建立一個可重用固定線程數的線程池        ExecutorService pool = Executors.newCachedThreadPool();        //建立實現了Runnable介面對象,Thread對象當然也實現了Runnable介面        Thread t1 = new MyThread();        Thread t2 = new MyThread();        Thread t3 = new MyThread();        Thread t4 = new MyThread();        Thread t5 = new MyThread();        //將線程放入池中進行執行        pool.execute(t1);        pool.execute(t2);        pool.execute(t3);        pool.execute(t4);        pool.execute(t5);        //關閉線程池        pool.shutdown();        /*         pool-1-thread-1正在執行...         pool-1-thread-2正在執行...         pool-1-thread-1正在執行...         pool-1-thread-3正在執行...         pool-1-thread-1正在執行...         */    }    @Test    public void testScheduledThreadPoolExecutor() {        ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);        exec.scheduleAtFixedRate(new Runnable() {//每隔一段時間就觸發異常            public void run() {                System.out.println("================");            }        }, 1000, 5000, TimeUnit.MILLISECONDS);        exec.scheduleAtFixedRate(new Runnable() {//每隔一段時間列印系統時間,證明兩者是互不影響的            public void run() {                System.out.println(System.nanoTime());            }        }, 1000, 2000, TimeUnit.MILLISECONDS);    }    /**     ================     440697961331385     440699965178923     440701962726589     ================     440703964380898     440705963957505     ================     440707961439581     440709966042376     440711964335904     ================     */}

  

          

Java線程池

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.