Android中的線程池來源于Java中的Executor接口,真正的線程池實(shí)現(xiàn)為ThreadPoolExecutor试读,它提供參數(shù)來配置線程池。既然提到線程池,首先得了解線程池有什么有點(diǎn)裂逐,線程池的優(yōu)點(diǎn)主要有以下3點(diǎn):
- 線程重用,通過重用線程池中線程避免反復(fù)創(chuàng)建和銷毀縣城帶來的性能開銷問題泣栈。
- 控制并發(fā)數(shù)卜高,避免大量線程同時工作搶占系統(tǒng)資源造成阻塞。
- 簡單的線程管理南片,實(shí)現(xiàn)定時執(zhí)行等功能掺涛。
一 ThreadPoolExecutor
- ThreadPoolExecutor 構(gòu)造器
//使用給定的參數(shù)和默認(rèn)線程工廠、拒絕執(zhí)行的Handler創(chuàng)建一個新的ThreadPoolExecutor
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
//使用給定的參數(shù)和拒絕執(zhí)行的Handler創(chuàng)建一個新的ThreadPoolExecutor疼进。
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory)
//使用給定的參數(shù)和默認(rèn)線程工廠創(chuàng)建一個新的ThreadPoolExecutor
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
//使用給定的參數(shù)創(chuàng)建一個新的ThreadPoolExecutor
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
- ThreadPoolExecutor 構(gòu)造器參數(shù)說明
- corePoolSize 核心線程數(shù)(常駐線程數(shù))
一直保持在線程池的線程數(shù)薪缆,空閑狀態(tài)也不會退出,除非設(shè)置allowCoreThreadTimeOut為true - maximumPoolSize 最大線程數(shù)
線程池中允許存在的最大線程數(shù) - keepAliveTime 保持活躍時間
當(dāng)線程數(shù)大于核心線程數(shù)時伞广,這是超出空閑線程在終止之前等待新任務(wù)的最大時間拣帽。當(dāng)allowCoreThreadTimeOut為true時,也適用與核心線程 - unit 單位
keepAliveTime參數(shù)的時間單位 - workQueue 任務(wù)隊(duì)列
在執(zhí)行任務(wù)之前用于保存任務(wù)的隊(duì)列嚼锄。 該隊(duì)列將僅保存由(Runnable的execute)方法提交的任務(wù)减拭。 - threadFactory 線程工廠
executor創(chuàng)建新線程的時候使用 - handler 拒絕執(zhí)行的handler
當(dāng)線程池?zé)o法執(zhí)行新任務(wù),導(dǎo)致執(zhí)行被阻止時使用的處理程序区丑,可能因?yàn)榫€程達(dá)到線程限制和隊(duì)列容量
- ThreadPoolExecutor執(zhí)行任務(wù)時大致規(guī)則
- 線程池中線程數(shù)小于核心線程數(shù)拧粪,會直接啟動一個核心線程來執(zhí)行新任務(wù)
- 線程池中線程數(shù)大于等于核心線程數(shù), 將會將新任務(wù)存放到任務(wù)隊(duì)列等待執(zhí)行
- 線程池中線程數(shù)大于等于核心線程數(shù)刊苍,且任務(wù)隊(duì)列已滿既们,但線程池中線程數(shù)小于最大線程數(shù),將會啟動一個非核心線程來執(zhí)行任務(wù)
- 線程池中線程數(shù)大于等于最大線程數(shù)正什,那么就會拒絕執(zhí)行該任務(wù)啥纸,調(diào)用handler的rejectedException來通知調(diào)用者
- ThreadPoolExecutor在AsyncTask中的使用
private static final String LOG_TAG = "AsyncTask";
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final int KEEP_ALIVE = 1;
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
/**
* An {@link Executor} that can be used to execute tasks in parallel.
*/
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
通過源碼,我們可以看到AsyncTask的THREAD_POOL_EXECUTOR屬性配置如下:
- 核心線程數(shù)(CORE_POOL_SIZE)為CPU核心數(shù)+1
- 最大線程數(shù)(MAXIMUM_POOL_SIZE)為CPU核心數(shù) * 2 + 1
- 非核心線程保持活躍時間為1婴氮,單位為秒
- 任務(wù)隊(duì)列容量為128
以上對ThreadPoolExecutor和AsyncTask中的ThreadPoolExecutor配置進(jìn)行了介紹斯棒。在Android中通過對ThreadPoolExecutor的配置實(shí)現(xiàn)了四類不同功能特性的線程池盾致,接下來我們就對Android中的這四類線程池進(jìn)行一個簡單介紹
二 FixedThreadPool
通過Executors.newFixedThreadPool創(chuàng)建一個線程池,它使用固定數(shù)量的線程操作了共享無界隊(duì)列荣暮。在任何時候庭惜,大多數(shù)線程都是主動處理任務(wù)的。如果在所有線程處于活動狀態(tài)時提交其他任務(wù)穗酥,則它們將在隊(duì)列中等待护赊,直到有線程空閑可用為止。如果任何線程在關(guān)閉前在執(zhí)行過程中失敗砾跃,如果需要執(zhí)行后續(xù)任務(wù)骏啰,則新線程將取代它。線程池中線程會一致存在抽高,直到線程池明確關(guān)閉(shutdown)判耕。下面是它的實(shí)現(xiàn),可以看到它只有不會被回收的核心線程翘骂,隊(duì)列大小也沒有限制壁熄。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
三 CachedThreadPool
通過Executors.newCachedThreadPool創(chuàng)建一個線程池,根據(jù)需要創(chuàng)建新線程碳竟,但在可用線程時將重用以前構(gòu)建的線程草丧。這些池通常會提高執(zhí)行許多短期異步任務(wù)的程序的性能。如果先前創(chuàng)建線程可用的話瞭亮,調(diào)用將重用先前構(gòu)建的線程方仿。如果沒有現(xiàn)有的線程可用固棚,一個新線程將被創(chuàng)建并添加到池统翩。未使用六十秒的線程被終止并從緩存中移除。因此此洲,空閑時間足夠長的池不會消耗任何系統(tǒng)資源厂汗。下面是它的實(shí)現(xiàn),可以看到與ThreadPoolExecutor不同的是它沒有核心線程呜师,最大線程數(shù)為Integer.MAX_VALUE娶桦,且CachedThreadPool的任務(wù)隊(duì)列是一個SynchronousQueue的空集合,這將導(dǎo)致任務(wù)會被立即執(zhí)行汁汗,所以這類線程比較適合執(zhí)行大量耗時較少的任務(wù)衷畦。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
四 ScheduledThreadPool
通過Executors.newScheduledThreadPoo創(chuàng)建一個線程池,可以在給定延遲后調(diào)度命令運(yùn)行知牌,或定期執(zhí)行命令祈争。它有數(shù)量固定的核心線程,且有數(shù)量無限多的非核心線程角寸,但是它的非核心線程超時時間是0s菩混,所以非核心線程一旦空閑立馬就會被回收忿墅。這類線程池適合用于執(zhí)行定時任務(wù)和固定周期的重復(fù)任務(wù)。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
五 newSingleThreadScheduledExecutor
通過Executors.newSingleThreadScheduledExecutor創(chuàng)建一個單線程執(zhí)行器沮峡,可以在給定延遲后調(diào)度命令運(yùn)行疚脐,或定期執(zhí)行命令。任務(wù)是按順序執(zhí)行的邢疙,在任何給定的時間內(nèi)都不會有一個任務(wù)處于活動狀態(tài)棍弄,讓調(diào)用者可以忽略線程同步問題。
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
六 線程池一般用法
- shutDown()疟游,關(guān)閉線程池照卦,需要執(zhí)行完已提交的任務(wù)
- shutDownNow(),關(guān)閉線程池乡摹,并嘗試結(jié)束已提交的任務(wù)
- allowCoreThreadTimeOut(boolen)役耕,允許核心線程閑置超時回收
- execute(),提交任務(wù)無返回值
- submit()聪廉,提交任務(wù)有返回值
除了上面4種線程池瞬痘,還可以根據(jù)實(shí)際需求自定義線程池。
七 自定義線程池
ExecutorService mExecutor = Executors.newFixedThreadPool(5);
execute()方法板熊,接收一個Runnable對象作為參數(shù)框全,異步執(zhí)行。
Runnable myRunnable = new Runnable() {
@Override
public void run() {
Log.i("myRunnable", "run");
}
};
mExecutor.execute(myRunnable);