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