android中的线程池学习笔记
閱讀書籍: Android開發藝術探索 Android開發進階從小工到專家
對線程池原理的簡單理解:
創建多個線程并且進行管理,提交的任務會被線程池指派給其中的線程進行執行,通過線程池的統一調度和管理使得多線程的使用更簡單,高效.
使用線程池的優勢:
1.重用線程池中的線程,避免因為線程的創建和銷毀所帶來的性能開銷.
2.能有效控制線程池的最大并發數,避免大量的線程之間因互相搶占系統資源而導致的阻塞現象.
3.能夠對線程進行簡單的管理,并提供定時執行以及指定間隔循環執行等功能.
ThreadPoolExecutor
Android中的線程池都是直接或者間接通過配置ThreadPoolExecutor來實現的,通過不同的參數可以創建不同的線程池.
ThreadPoolExecutor類中有四個構造方法,下面是比較常用的一個.
corePoolSize
線程池的核心線程數,默認情況下,核心線程會在線程池中一直存活,即使他們處于閑置狀態.可以通過設置ThreadPoolExecutor的allowCoreThreadTimeOut屬性為true,這樣閑置的核心線程在等待新任務到來時會有超時策略,這個時間間隔由keepAliveTime所指定.
maximumPoolSize
線程池所能容納的最大線程數,當活動線程數達到這個數值后,后續的新任務將會被阻塞.
keepAliveTime
非核心線程閑置時的超時時長,閑置超過這個時長,非核心線程就會被回收.當ThreadPoolExecutor的allowCoreThreadTimeOut屬性設置為true時,keepAliveTime同樣會作用于核心線程.
unit
用于指定keepAliveTime參數的時間單位,這是一個枚舉,例如TimeUnit.MILLISECONDS等.
workQueue
線程池中的任務隊列,通過線程池的execute方法提交的Runnable對象會存儲在這個參數中.
threadFactory
線程工廠,為線程池提供創建新線程的功能.ThreadFactory是一個接口,它只有一個方法: Thread newThread(Runnable r).
除了以上這些參數外,還有一個不常用的參數RejectedExecutionHandler handler.當線程池無法執行新任務時(這可能是由于任務隊列已滿或者是無法成功執行任務),會調用handler的rejectedExecution方法來通知調用者,默認情況下該方法會直接拋出一個RejectedExecutionException.(該參數不常用)
ThreadPoolExecutor執行任務時,大致遵循如下規則:
(1)如果線程池中的線程數量未達到核心線程數,那么會直接啟動一個核心線程來執行任務.
(2)如果線程池中的線程數量已經達到或者超過核心線程的數量,那么任務會被插到任務隊列中排隊等待執行.
(3)如果在步驟2中無法將任務插入到任務隊列中(這往往是由于任務隊列已滿),這個時候如果線程數量未達到線程池規定的最大值,那么會立刻啟動一個非核心線程來執行任務.
(4)如果步驟3中線程數量已經達到線程池規定的最大值,那么就拒絕執行此任務,ThreadPoolExecutor會調用RejectedExecutionHandler的RejectedExecution方法來通知調用者.
線程池的分類
從線程池的功能特性上來說,Android的線程池主要分為四類,這4類線程池可以通過Executors所提供的工廠方法來得到.
FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}特點:
從參數中可以看到FixedThreadPool中只有核心線程并且這些核心線程沒有超時機制,任務隊列也是沒有大小限制的.
FixedThreadPool線程數量固定,當線程處于空閑狀態時,它們并不會被回收,除非線程池被關閉了.當所有的線程都處于活動狀態時,新任務都會處于等待狀態,直到有線程空閑出來.
由于只有核心線程并且這些核心線程不會被回收,這意味著它能夠更加快速地響應外界的請求.
使用場景:
對于Android平臺,由于資源有限,最常使用的就是通過Executors.newFixedThreadPool(int size)來啟動固定數量的線程池
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);fixedThreadPool(3);}private static void fixedThreadPool(int size) {ExecutorService executorService = Executors.newFixedThreadPool(size);for (int i = 0;i < MAX; i++) {executorService.execute(new Runnable() {@Overridepublic void run() {SystemClock.sleep(2000);Log.i("MainActivity","執行線程: " + Thread.currentThread().getName());}});}}執行結果:
03-31 16:03:01.016 25903-25934/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-1 03-31 16:03:01.016 25903-25935/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-2 03-31 16:03:01.016 25903-25936/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-3 03-31 16:03:03.016 25903-25934/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-1 03-31 16:03:03.016 25903-25935/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-2 03-31 16:03:03.016 25903-25936/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-3 03-31 16:03:05.016 25903-25935/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-2 03-31 16:03:05.016 25903-25934/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-1 03-31 16:03:05.016 25903-25936/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-3 03-31 16:03:07.016 25903-25935/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-2從結果中可以看到,每隔2s有三個線程同時運行,而且是相同的三個線程.
CachedThreadPool
public static ExecutorService newCachedThreadPool() {return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}特點
從參數中可以看出,它是一種線程數量不定的線程池,而且沒有核心線程,只有非核心線程,并且最大線程數為Integer.MAX_VALUE(由于Integer.MAX_VALUE是一個很大的數(0x7FFFFFFF),實際上就相當于最大線程數可以任意大).有60s超時機制,當整個線程池都處于閑置狀態時,線程池中的線程都會超時而被停止,這個時候幾乎不占用任何系統資源.
使用場景
從CachedThreadPool的特性來看,這類線程池比較適合執行大量的耗時較少的任務.(以空間換時間)
//省略onCreate函數private static void cachedThreadPool() {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0;i < MAX; i++) {executorService.execute(new Runnable() {@Overridepublic void run() {SystemClock.sleep(2000);Log.i("MainActivity","執行線程: " + Thread.currentThread().getName());}});}}執行結果:
03-31 16:48:47.776 6757-6791/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-7 03-31 16:48:47.776 6757-6785/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-1 03-31 16:48:47.776 6757-6787/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-3 03-31 16:48:47.776 6757-6788/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-4 03-31 16:48:47.776 6757-6789/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-5 03-31 16:48:47.776 6757-6790/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-6 03-31 16:48:47.776 6757-6786/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-2 03-31 16:48:47.776 6757-6792/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-8 03-31 16:48:47.776 6757-6793/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-9 03-31 16:48:47.776 6757-6794/com.example.janiszhang.threadpooldemo I/MainActivity: 執行線程: pool-1-thread-10從結果來看,每次調用execute,(在沒有空閑線程可用情況下)就會立即啟動一個線程,所有任務幾乎在同時完成.
ScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue());}特點及使用場景:
從參數列表可以看出,它的核心線程數是固定的,非核心線程數沒有限制.
這類線程池主要用于執行定時任務和具有固定周期的重復任務.
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);//2000ms后執行commandscheduledExecutorService.schedule(new Runnable() {@Overridepublic void run() {SystemClock.sleep(2000);Log.i("MainActivity", "執行線程: " + Thread.currentThread().getName());}},2000, TimeUnit.MILLISECONDS);//延遲10ms后,每隔1000ms執行一次commandscheduledExecutorService.scheduleAtFixedRate(new Runnable() {@Overridepublic void run() {SystemClock.sleep(2000);Log.i("MainActivity", "執行線程: " + Thread.currentThread().getName());}},10,1000,TimeUnit.MILLISECONDS);}SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}特點與使用場景:
這類線程池內部只有一個核心線程,它確保所有的任務都在同一個線程中按順序執行.SingleThreadExecutor的意義在于統一所有的外界任務到一個線程中,這使得在這些任務之間不需要處理線程同步的問題.
線程池的最佳大小
線程池的最佳大小取決于可用處理器的數目以及工作隊列中的任務性質.
若在一個具有N個處理器的系統上只有一個工作隊列,其中全部是計算性質的任務,在線程池具有N或N+1個線程時一般會獲得最大的CPU利用率.
對于那些可能需要等待I/O完成的任務,需要線程池的大小超過可用處理器的數目,因為并不是所有線程都一直在工作.
轉載于:https://www.cnblogs.com/happyhacking/p/5340007.html
總結
以上是生活随笔為你收集整理的android中的线程池学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端神器avalonJS入门(二)
- 下一篇: SNAT,是源地址转换,其作用是将ip数