眾所周知,在UI系統(tǒng)中進(jìn)行一些耗時(shí)操作,都會(huì)導(dǎo)致卡頓現(xiàn)象,因?yàn)橐淮嗡⑿略?6ms,如果當(dāng)次操作過(guò)了這個(gè)時(shí)間,那么用戶(hù)就能感覺(jué)到明顯的卡頓,甚至引起ANR 。
對(duì)于這種情況,一般都是再起一個(gè)線(xiàn)程,進(jìn)行一些耗時(shí)的操作,通過(guò)繼承Thread 或者實(shí)現(xiàn)Runnable接口,重寫(xiě)run方法,來(lái)實(shí)現(xiàn)創(chuàng)建新線(xiàn)程,進(jìn)行耗時(shí)操作的需求.由于java的單繼承關(guān)系,首推實(shí)現(xiàn)Runnable方法,這樣不會(huì)太過(guò)臃腫。
private void runThread() {
Thread t1 = new Thread(new MyRunnable(this), "郭富城");
t1.start();
//強(qiáng)調(diào)一點(diǎn),調(diào)用run方法是真的調(diào)用方法,而調(diào)用start方法則會(huì)創(chuàng)建新線(xiàn)程去調(diào)用這個(gè)run方法。
}
//實(shí)現(xiàn)runnable方法 至于繼承Thread方法的代碼 ,就不寫(xiě)了
static class MyRunnable implements Runnable {
private WeakReference<MainActivity> reference;
MyRunnable(MainActivity activity) {
reference = new WeakReference<MainActivity>(activity);
}
@Override
public void run() {
if (reference != null) {
MainActivity activity = reference.get();
if (activity != null) {
//子線(xiàn)程不能彈toast的 所以加了點(diǎn)東西
Looper.prepare();
Toast.makeText(activity, Thread.currentThread().getName() + " is Runing", Toast.LENGTH_SHORT).show();
Looper.loop();
}
}
}
}
另外,jdk1.5版本以后,就新加了個(gè)Callable接口,相較于Runnable接口,他可以定義返回值,并且可以?huà)伋霎惓#枰獙?shí)現(xiàn)的方法也從run方法變成了call方法。還有一點(diǎn)很有意思,他返回一個(gè)Future對(duì)象,通過(guò)這個(gè)對(duì)象,我們可以知道任務(wù)的進(jìn)行程序,并且可以關(guān)閉這個(gè)任務(wù)。Thread是不支持這個(gè)接口的 ,所以如果要用Callable,就需要用上FutureTask.
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
簡(jiǎn)單的說(shuō),F(xiàn)utureTask是一種可以取消的異步任務(wù),異步執(zhí)行任務(wù), 可以開(kāi)始、取消以及查看任務(wù)是否完成, 如果任務(wù)沒(méi)有執(zhí)行完,get方法會(huì)導(dǎo)致線(xiàn)程阻塞, 一旦一個(gè)執(zhí)行任務(wù)已經(jīng)完成就不能再次開(kāi)始和結(jié)束(除非執(zhí)行時(shí)通過(guò)runAndReset()方法.另外,F(xiàn)utureTask也同樣支持Runnable接口。
private void runFutureTask() {
//創(chuàng)建線(xiàn)程池 不用線(xiàn)程池 直接用future也可以的
final ExecutorService exec = Executors.newFixedThreadPool(5);
//創(chuàng)建futureTask任務(wù)
final FutureTask<String> ft = new FutureTask<String>(new MyCallable());
// 執(zhí)行也可以 提交也可以 還有種invokeAll方法
exec.execute(ft);
// exec.submit(ft);
new Thread(new Runnable() {
@Override
public void run() {
try {
//get方法會(huì)自動(dòng)阻塞當(dāng)前線(xiàn)程 直到拿到結(jié)果
//所以不要放在主線(xiàn)程去get 不然就卡住了 雖然我試過(guò)卡個(gè)15秒也沒(méi)事
final String text = ft.get();
Looper.prepare();
Toast.makeText(FutureTaskActivity.this, text, Toast.LENGTH_SHORT).show();
Looper.loop();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}).start();
//用完線(xiàn)程池 記得關(guān)閉掉
exec.shutdown();
}
static class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(3000);
return "代碼讓我快樂(lè),代碼讓我禿頂";
}
}
線(xiàn)程是CPU調(diào)度的最小單元,對(duì)于線(xiàn)程的創(chuàng)建,銷(xiāo)毀,調(diào)度,其實(shí)也是在耗費(fèi)一定資源的,特別是某些情況下,你需要?jiǎng)?chuàng)建一堆線(xiàn)程進(jìn)行一些簡(jiǎn)單的耗時(shí)操作時(shí),這個(gè)資源的消耗量還是非常大的,所以就有線(xiàn)程池的需求了。
我們來(lái)總結(jié)一下優(yōu)點(diǎn)吧。
1.重用線(xiàn)程池中的線(xiàn)程,避免頻繁地創(chuàng)建和銷(xiāo)毀線(xiàn)程帶來(lái)的性能消耗;
2.有效控制線(xiàn)程的最大并發(fā)數(shù)量,防止線(xiàn)程過(guò)大導(dǎo)致?lián)屨假Y源造成系統(tǒng)阻塞;
3.可以對(duì)線(xiàn)程進(jìn)行一定地管理。
使用線(xiàn)程池 相對(duì)于每次都new 線(xiàn)程,性能會(huì)好很多,并且可以統(tǒng)一管理,功能上也能有所改善,如果需要定時(shí)執(zhí)行,定期執(zhí)行,線(xiàn)程中斷等。
減少內(nèi)存開(kāi)銷(xiāo)。
ThreadPoolExecutor:
ExecutorService是最初的線(xiàn)程池接口,ThreadPoolExecutor類(lèi)是對(duì)線(xiàn)程池的具體實(shí)現(xiàn),它通過(guò)構(gòu)造方法來(lái)配置線(xiàn)程池的參數(shù),我們來(lái)分析一下它常用的構(gòu)造函數(shù)吧。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
參數(shù)解釋?zhuān)?
corePoolSize,線(xiàn)程池中核心線(xiàn)程的數(shù)量,默認(rèn)情況下,即使核心線(xiàn)程沒(méi)有任務(wù)在執(zhí)行它也存在的,我們固定一定數(shù)量的核心線(xiàn)程且它一直存活這樣就避免了一般情況下CPU創(chuàng)建和銷(xiāo)毀線(xiàn)程帶來(lái)的開(kāi)銷(xiāo)。我們?nèi)绻麑hreadPoolExecutor的allowCoreThreadTimeOut屬性設(shè)置為true,那么閑置的核心線(xiàn)程就會(huì)有超時(shí)策略,這個(gè)時(shí)間由keepAliveTime來(lái)設(shè)定,即keepAliveTime時(shí)間內(nèi)如果核心線(xiàn)程沒(méi)有回應(yīng)則該線(xiàn)程就會(huì)被終止。allowCoreThreadTimeOut默認(rèn)為false,核心線(xiàn)程沒(méi)有超時(shí)時(shí)間。
maximumPoolSize,線(xiàn)程池中的最大線(xiàn)程數(shù),當(dāng)任務(wù)數(shù)量超過(guò)最大線(xiàn)程數(shù)時(shí)其它任務(wù)可能就會(huì)被阻塞。最大線(xiàn)程數(shù)=核心線(xiàn)程+非核心線(xiàn)程。非核心線(xiàn)程只有當(dāng)核心線(xiàn)程不夠用且線(xiàn)程池有空余時(shí)才會(huì)被創(chuàng)建,執(zhí)行完任務(wù)后非核心線(xiàn)程會(huì)被銷(xiāo)毀。
keepAliveTime,非核心線(xiàn)程的超時(shí)時(shí)長(zhǎng),當(dāng)執(zhí)行時(shí)間超過(guò)這個(gè)時(shí)間時(shí),非核心線(xiàn)程就會(huì)被回收。當(dāng)allowCoreThreadTimeOut設(shè)置為true時(shí),此屬性也作用在核心線(xiàn)程上。
unit,枚舉時(shí)間單位,TimeUnit。
workQueue,線(xiàn)程池中的任務(wù)隊(duì)列,我們提交給線(xiàn)程池的runnable會(huì)被存儲(chǔ)在這個(gè)對(duì)象上。
線(xiàn)程池的分配遵循這樣的規(guī)則:
當(dāng)線(xiàn)程池中的核心線(xiàn)程數(shù)量未達(dá)到最大線(xiàn)程數(shù)時(shí),啟動(dòng)一個(gè)核心線(xiàn)程去執(zhí)行任務(wù);
如果線(xiàn)程池中的核心線(xiàn)程數(shù)量達(dá)到最大線(xiàn)程數(shù)時(shí),那么任務(wù)會(huì)被插入到任務(wù)隊(duì)列中排隊(duì)等待執(zhí)行;
如果在上一步驟中任務(wù)隊(duì)列已滿(mǎn)但是線(xiàn)程池中線(xiàn)程數(shù)量未達(dá)到限定線(xiàn)程總數(shù),那么啟動(dòng)一個(gè)非核心線(xiàn)程來(lái)處理任務(wù);
如果上一步驟中線(xiàn)程數(shù)量達(dá)到了限定線(xiàn)程總量,那么線(xiàn)程池則拒絕執(zhí)行該任務(wù),且ThreadPoolExecutor會(huì)調(diào)用RejectedtionHandler的rejectedExecution方法來(lái)通知調(diào)用者。
四種線(xiàn)程池 都可以通過(guò)Executors提供:
- newCachedThreadPool:創(chuàng)建一個(gè)可緩存線(xiàn)程池,他是一個(gè)不限容量的線(xiàn)程池,其中創(chuàng)建的所有的線(xiàn)程都是非核心線(xiàn)程,如果線(xiàn)程池長(zhǎng)度超過(guò)處理需要,超時(shí)時(shí)間設(shè)置為60s,如果當(dāng)前沒(méi)有任務(wù),會(huì)回收空閑線(xiàn)程,若無(wú)可回收,則新建線(xiàn)程。用于執(zhí)行一些生存期很短的異步型任務(wù)
public static ExecutorService new CachedThreadPool(){
return new ThreadPoolExecutor(
0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>()
);
}
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
- newFixedThreadPool :創(chuàng)建一個(gè)定長(zhǎng)線(xiàn)程池,可控制線(xiàn)程最大并發(fā)數(shù),超出的線(xiàn)程會(huì)在隊(duì)列中等待。池線(xiàn)程數(shù)固定,創(chuàng)建的線(xiàn)程會(huì)一直存在。它沒(méi)有超時(shí)機(jī)制并且等待隊(duì)列無(wú)限常,所以fixedThreadPool多數(shù)針對(duì)一些很穩(wěn)定很固定的正規(guī)并發(fā)線(xiàn)程,多用于服務(wù)器。
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(
nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()
);
}
//創(chuàng)建線(xiàn)程池
ExecutorService mExecutor = Executors.newFixedThreadPool(5);//參數(shù)即核心線(xiàn)程數(shù)
- newScheduledThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線(xiàn)程池,其實(shí)他將上面兩種線(xiàn)程池的優(yōu)點(diǎn)全部集結(jié)成一塊,他有一定數(shù)量的核心線(xiàn)程,并且無(wú)限容量的非核心線(xiàn)程,區(qū)別在于非核心線(xiàn)程的超時(shí)時(shí)間設(shè)定為0秒,即一旦空閑,立馬回收,支持定時(shí)及周期性任務(wù)執(zhí)行。
public static ScheduledThreadPool newScheduledThreadPool(int corePoolSize){
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize){
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);//核心線(xiàn)程數(shù)
- newSingleThreadExecutor 創(chuàng)建一個(gè)單線(xiàn)程化的線(xiàn)程池,他只有一個(gè)核心線(xiàn)程,它也只會(huì)用唯一的工作線(xiàn)程來(lái)執(zhí)行任務(wù),可以讓調(diào)用者忽略線(xiàn)程同步的問(wèn)題。
public static ExecutorService newSingleThreadExecutor(){
return new FinalizableDelegatedExecutorService(
new ThreadPoolExecutor(
1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
線(xiàn)程池一般用法
shutDown(),關(guān)閉線(xiàn)程池,需要執(zhí)行完已提交的任務(wù);
shutDownNow(),關(guān)閉線(xiàn)程池,并嘗試結(jié)束已提交的任務(wù);
allowCoreThreadTimeOut(boolen),允許核心線(xiàn)程閑置超時(shí)回收;
execute(),提交任務(wù)無(wú)返回值;
submit(),提交任務(wù)有返回值;
newCachedThreadPool緩存線(xiàn)程池,如果線(xiàn)程超出則靈活回收,如果不夠則創(chuàng)建
newFixedThreadPool 定長(zhǎng)線(xiàn)程池,可以設(shè)置最大線(xiàn)程數(shù),超出的任務(wù)在隊(duì)列中等候。
newScheduledThreadPool 也是定長(zhǎng)線(xiàn)程池 ,支持定時(shí)及周期性任務(wù)。
newSingleThreadExecutor 單線(xiàn)程化的線(xiàn)程池,任務(wù)根據(jù)加入順序在隊(duì)列中慢慢等待執(zhí)行。
除了以上這些,在Android中充當(dāng)線(xiàn)程的角色還有AsyncTask、HandlerThread、IntentService。它們本質(zhì)上都是由Handler+Thread來(lái)構(gòu)成的。
AsyncTask,它封裝了線(xiàn)程池和Handler,主要為我們?cè)谧泳€(xiàn)程中更新UI提供便利。
HandlerThread,它是個(gè)具有消息隊(duì)列的線(xiàn)程,可以方便我們?cè)谧泳€(xiàn)程中處理不同的事務(wù)。
IntentService,我們可以將它看做為HandlerThread的升級(jí)版,它是服務(wù),優(yōu)先級(jí)更高。
參考
http://blog.csdn.net/weixin_36244867/article/details/72832632
http://blog.csdn.net/linchunquan/article/details/22382487
http://www.hchstudio.cn/2017/04/01/FutureTask%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/
http://www.cnblogs.com/wenjiang/archive/2012/09/02/2668089.html