線程池的優勢:多線程
Android中的線程來源於Java中的Executor,實現類是ThreadPoolExecutor,ThreadPoolExecutor經過構造方法的一系列參數,來構成不一樣配置的線程池。經常使用的構造方法有下面四個:ide
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
下面介紹上面說到的經常使用的四種隊列,在這以前先根據上面的參數分析一下幫助理解:有核心線程、非核心線程、任務隊列三個角色,他們能夠根據當前配置,對每一個新來的任務作出處理(處理就是要麼分配線程去執行任務,要麼把任務存到任務隊列裏等待分配線程)。那麼,三個角色能夠設計以下:
有限個核心線程 + 任務隊列(隊列大小可配置)+ 無限個非核心線程
(確切的說是corePoolSize個核心線程,maximumPoolSize - corePoolSize個非核心線程)工具
不難理解,任務不少的時候,核心線程不夠用了就存到任務隊列裏,隊列存滿了,就建立非核心線程執行任務(就像節假日客運站臨時加車同樣)。這樣設計包含了兩種極端狀況,就是隊列大小是0和隊列無限大,因此具體設計以下三種狀況:性能
這三種設計,就對應了workQueue參數的三種隊列:SynchronousQueue, LinkedBlockingDeque, ArrayBlockingQueue.net
收到新任務時,直接交給線程處理,若是全部線程都在工做,那麼新建線程來處理這個任務。若是將maximumPoolSize指定成Integer.MAX_VALUE,就是無限個線程。
(對應上面的第1種設計)線程
這個隊列沒有大小限制。當接收到新任務時,若是當前線程小於核心線程數,則新建核心線程處理任務。若是當前線程數等於核心線程數,則進入隊列等待。因爲隊列沒有大小限制,也就致使了 maximumPoolSize 的設定失效,由於這時最大線程數不會超過核心線程數。
(對應上面第2種設計)設計
能夠限定隊列長度,收到任務的時候,若是沒有達到corePoolSize的值,則新建核心線程執行任務,若是達到了,入隊等候。若是隊列已滿,則新建非核心線程執行任務。若是達到了maximumPoolSize,就會發生錯誤。
(對應上面第3種設計)code
隊列內元素必須實現 Delayed 接口,這就意味着你傳進去的任務必須先實現 Delayed 接口。這個隊列接收到任務時,首先先入隊,只有達到了指定的延時時間,纔會執行任務。blog
現實中,隊列不可能無限大,非核心線程不可能有無數個,那麼上面幾種隊列就有超出線程總數的狀況,這種狀況只須要配置ThreadPoolExecutor的第7個參數RejectedExecutionHandler便可(能夠翻到上面從新看下參數說明)。接口
下面介紹4種系統提供的配置好的線程池,固然,若是理解了上面的任務隊列,本身配置出相同的線程池是很簡單的。這4種線程池使用系統的工具類Executors來建立,以下:
//下面加了參數1的是由於沒有無參數的重載方法。 Executors.newFixedThreadPool(1); Executors.newCachedThreadPool(); Executors.newScheduledThreadPool(1); Executors.newSingleThreadExecutor();
對應:有限個核心線程+任務隊列(隊列無限大) --> LinkedBlockingQueue
它的建立方法須要傳入參數來指定核心線程數。功能特色很好理解,下面是藝術探索中對它的描述:
它是一種線程數量固定的線程池,當線程處於空閒狀態時,它們並不會被回收,除非線程池被關閉。當全部線程都處於活動狀態時,新任務就會處於等待狀態,直到有線程空閒出來。因爲FixedThreadPool只有核心線程而且這些核心線程不會被回收,這意味着它可以更加快速地響應外界請求。經過newFixedThreadPool方法的源碼能夠發現FixedThreadPool中只有核心線程沒有超時機制,另外任務隊列也是沒有大小限制的。
對應:有限個核心線程+無限個非核心線程 --> SynchronousQueue
它的核心線程數是0,因此它的建立方法不須要參數,下面是藝術探索中對它的描述:
它是一種線程數量不定的線程池,它只有非核心線程,而且最大線程數爲Integer.MAX_VALUE。因爲Integer.MAX_VALUE是一個很大的數,實際上就至關於最大線程數能夠任意大。當線程池中的線程都處於活動狀態時,線程池會建立新的線程來處理新任務,不然就會利用空閒線程來處理新任務。線程池中的空閒線程都有超時機制,超時時長是60秒,超過60秒閒置的線程就會被回收。和FixedThreadPool不一樣的是,CachedThreadPool的任務隊列其實至關於一個空集合,這將致使任何任務都會被當即執行。這類線程池比較適合執行大量的耗時較少的任務。當整個線程池處於閒置狀態時,全部線程都會超時而被中止,這個時候CachedThreadPool中其實是沒有任何線程的,它幾乎是不佔任何系統資源的。
對應:DelayQueue
它的建立方法須要參數來指定核心線程數,描述以下:
它的核心線程數是固定的,而非核心線程數是沒有限制的。這個線程池主要用於執行定時任務和有固定週期的重複任務。
對應:有限個核心線程+任務隊列(隊列無限大) --> LinkedBlockingQueue
與FixedThreadPool的區別在於,SingleThreadExecutor只有一個核心線程,因此它的建立方法無需參數。描述以下:
這類線程池內部只有一個核心線程,它確保全部的任務都在同一個線程中按順序執行。意義在於統一全部外界任務到一個線程中,這使得在這些任務之間不須要處理線程同步的問題。
最後是使用線程池的幾個示例:
Runnable myRunnable = new Runnable() { @Override public void run() { SystemClock.sleep(2000); } }; //本身配置的線程池 ThreadPoolExecutor myExecutor = new ThreadPoolExecutor(2, 10, 5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); //執行myRunnable任務 myExecutor.execute(myRunnable); //系統提供的線程池 ExecutorService fixedExecutor = Executors.newFixedThreadPool(1); //執行myRunnable任務 fixedExecutor.execute(myRunnable); //系統提供的線程池 ScheduledExecutorService sExecutor = Executors.newScheduledThreadPool(1); //2000ms後執行myRunnable sExecutor.schedule(myRunnable, 2000, TimeUnit.MILLISECONDS); //10ms後,每隔1000ms執行一次myRunnable sExecutor.scheduleAtFixedRate(myRunnable, 10, 1000, TimeUnit.MILLISECONDS);
《Android開發藝術探索》
Java多線程-線程池ThreadPoolExecutor構造方法和規則
線程池,這一篇或許就夠了