讀完開發(fā)藝術(shù)探討做的一些總結(jié)。
介紹:
在操作系統(tǒng)中,線程是操作系統(tǒng)調(diào)度最小的單元风瘦,同時(shí)線程又是一種受限的資源系統(tǒng),既線程不可能無限制的生產(chǎn)公般,而且線程的創(chuàng)建和銷毀都會有相應(yīng)的開銷万搔。
在android開發(fā)中,從用途上來說官帘,android 主要分為主線程和子線程瞬雹,主線程負(fù)責(zé)處理和界面相關(guān)的事情,子線程往往處理耗時(shí)的操作刽虹。(在java中默認(rèn)情況下挖炬,一個(gè)進(jìn)程只有一個(gè)線程,這個(gè)線程就叫主線程状婶,主線程在任何時(shí)候都必須有較高的響應(yīng)速度意敛,否則就會產(chǎn)生一種界面卡頓的感覺。如果在主線程中執(zhí)行耗時(shí)操作那么容易導(dǎo)致程序無法及時(shí)響應(yīng)膛虫,這個(gè)時(shí)候子線程就派上用處草姻,子線程也叫工作線程,除了主線程意外的都是子線程)
通俗的理解就是一個(gè)公司一般只會有一位老板稍刀,老板多了做事情容易亂套撩独,每個(gè)子線程都是老板手下的業(yè)務(wù)人員,老板一般只處理大事件账月,負(fù)責(zé)一些活動(dòng)的簽字行為等综膀,當(dāng)事情的具體細(xì)節(jié)老板就會交給他手下的員工去處理,這樣就不會影響老板談其它的生意發(fā)家致富了局齿。
在android中除了Thread外剧劝,系統(tǒng)本身也有許多扮演子線程的角色,比如:
AsyncTask,IntentService等抓歼,不過這些本質(zhì)上依然是傳統(tǒng)的線程讥此。
Android線程池
優(yōu)點(diǎn):
1.重用線程池中的線程拢锹,避免因?yàn)榫€程的創(chuàng)建和銷毀所帶來的性能開銷。
2.有效的控制線程池的最大并發(fā)數(shù)萄喳,避免大量的線程之間因互相搶占系統(tǒng)資源而導(dǎo)致的阻塞現(xiàn)象卒稳。
3.能夠?qū)€程進(jìn)行簡單的管理,并提供定時(shí)執(zhí)行及指定間隔循環(huán)執(zhí)行等功能他巨。
Android中的線程池來源與java中的Executor,真正實(shí)現(xiàn)為ThreadPoolExecutor充坑。ThreadPoolExecutor提供了一系列參數(shù),通過不同的參數(shù)可以創(chuàng)建功效不同的線程池染突。接下來先介紹一下ThreadPoolExecutor捻爷。
ThreadPoolExecutor
首先看一下ThreadPoolExecutor比較常用的一個(gè)構(gòu)造方法:
corePoolSize (線程的核心數(shù),默認(rèn)情況下核心線程會一直在線程
中存活觉痛,跟allowCoreThreadTimeOut有關(guān))
maximumPoolSize (線程池能夠容納的最大線程數(shù)役衡,當(dāng)活動(dòng)線程
數(shù)大道這個(gè)數(shù)值后茵休,后續(xù)的新任務(wù)將會被阻塞)
keepAliveTime (非核心線程閑置的超時(shí)時(shí)長薪棒,超過后非核
心線程會被回收,allowCoreThreadTimeOut為true時(shí)榕莺,對核心線程
也有效)
unit (枚舉單位俐芯,代表keepAliveTime的時(shí)間單位)
workQueue (線程池中的任務(wù)列隊(duì),通過線程池的execute
方法提交的Runnable對象會存儲在這個(gè)參數(shù)中)
threadFactory (線程工廠钉鸯,為線程池提供創(chuàng)建新線程的功能
threadFactory是一個(gè)接口吧史,它只有一個(gè)方法:ThreadnewThread(Runnable r))
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
ThreadPoolExecutor執(zhí)行任務(wù)時(shí)候的大致規(guī)則:
1.如果線程池中的線程數(shù)量沒有大道核心線程的數(shù)量,那么會直接啟動(dòng)一個(gè)核心線程來執(zhí)行任務(wù)唠雕。
2.如果線程池中的線程數(shù)量已經(jīng)達(dá)到或者超過核心線程數(shù)量贸营,那么任務(wù)會被插入到任務(wù)列隊(duì)中排隊(duì)等待執(zhí)行。
3.如果步驟2中無法將任務(wù)插入到任務(wù)列隊(duì)中岩睁,這往往是由于任務(wù)列隊(duì)已滿钞脂,這個(gè)時(shí)候如果線程數(shù)量沒有達(dá)到線程池中規(guī)定的最大值,那么會立刻啟動(dòng)一個(gè)非核心線程來執(zhí)行任務(wù)捕儒。
4.如果步驟3中線程數(shù)量已經(jīng)達(dá)到線程池規(guī)定的最大值冰啃,那么就拒絕執(zhí)行此任務(wù),ThreadPoolExecutor會調(diào)用RejectedExecutionExecutionHandler的rejectedExecution方法來通知調(diào)用者刘莹。(參數(shù)不常用)
(allowCoreThreadTimeOut方法只有在ThreadPoolExecutor中實(shí)現(xiàn)了)
之前說到過的AsyncTask的源碼中就有ThreadPoolExecutor的具體實(shí)現(xiàn)阎毅,可以看一下,接下來自己簡單實(shí)現(xiàn)一個(gè)線程池:
private void initThreadPoolExecutor(){
int corePool = 5;
int maxPool = 10;
long keppTime = 10000;
//BlockingQueue是一個(gè)接口
BlockingDeque<Runnable> poolQueue = new LinkedBlockingDeque<>(100);
ThreadFactory threadFactory = new ThreadFactory() {
@Override
public Thread newThread(@NonNull Runnable r) {
return null;
}
};
Executor executor = new ThreadPoolExecutor(corePool,maxPool,keppTime, TimeUnit.MILLISECONDS,poolQueue,threadFactory);
}
每個(gè)參數(shù)之前的備注中有点弯,應(yīng)該很好理解其中的意思扇调。
在Android中常用的線程池有4種,它們都直接或者間接地通過配置ThreadPoolExecutor來實(shí)現(xiàn)自己的功能特性的,
在Executors中有很多工廠方法抢肛,可以直接實(shí)例出來這些對象肃拜。
1.FixedThreadPool
通過Executors的newFixedThreadPool方法來創(chuàng)建痴腌,我們首頁來看看他的實(shí)現(xiàn)方法:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
一般情況下,可以看到只用傳入一個(gè)線程的具體數(shù)量就可以了燃领,在其內(nèi)部中士聪,核心線程和最大線程是相同的,即代表只有核心線程猛蔽,這意味著它能夠更加快速的響應(yīng)外界的請求剥悟。而且超時(shí)為0代表當(dāng)線程為控件狀態(tài)時(shí),它們不會被回收曼库,除非線程池被關(guān)閉区岗。實(shí)例化的LinkedBlockingQueue長度不限,則代表新任務(wù)都會處于等待狀態(tài)毁枯,直到有線程空閑出來慈缔。其實(shí)就跟字面意思一樣,這是一個(gè)固定線程數(shù)的線程池种玛。
下面介紹一下簡單的使用方法:
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
ExecutorService fixed = Executors.newFixedThreadPool(5);
fixed.execute(runnable);
2.CachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
通過Executors的newExecutorService 方法來創(chuàng)建藐鹤,由上可以看到,它沒有核心線程赂韵,只有不限制的非核心線程娱节,而且有超時(shí)機(jī)制,當(dāng)超過60秒鐘后祭示,線程就會被回收肄满。由此可以看出只要有任務(wù)進(jìn)來時(shí),就會有線程去執(zhí)行质涛,當(dāng)任務(wù)完成一段時(shí)間后稠歉,線程就會被回收,當(dāng)閑置狀態(tài)的時(shí)候汇陆,線程池中實(shí)際上是沒有任務(wù)線程的怒炸,幾乎不占用任何系統(tǒng)資源。這類線程比較適合執(zhí)行大量的耗時(shí)較少的任務(wù)瞬测。
簡單使用方式:
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
ExecutorService cache = Executors.newCachedThreadPool();
cache.execute(runnable);
3.ScheduledThreadPoolExecutor
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
通過Executors的newScheduledThreadPool方法來創(chuàng)建横媚,核心線程固定,最大線程數(shù)量沒有限制月趟,當(dāng)非核心線程閑置時(shí)會被立刻回收灯蝴,其中queue的類型是一個(gè)DelayedWorkQueue(),則代表這是一個(gè)用來執(zhí)行延時(shí)任務(wù)孝宗,或者重復(fù)周期性的任務(wù)穷躁。
簡單使用方法:
ScheduledExecutorService schedule = Executors.newScheduledThreadPool(3);
//1000毫秒之后執(zhí)行
schedule.schedule(runnable,1000,TimeUnit.MILLISECONDS);
//1000毫秒后執(zhí)行,每隔10000毫秒執(zhí)行一次
schedule.scheduleAtFixedRate(runnable,1000,10000,TimeUnit.MILLISECONDS);
4.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
這個(gè)線程內(nèi)部只有一個(gè)核心線程,這么做可以確保所有的任務(wù)都在一個(gè)線程中按順序執(zhí)行问潭,這樣統(tǒng)一所有的外界任務(wù)到一個(gè)線程中猿诸,使得在這些任務(wù)之間不需要處理線程同步的問題。
簡單使用方式:
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
ExecutorService signle = Executors.newSingleThreadExecutor();
signle.execute(runnable);
其中當(dāng)線程不使用的時(shí)候可以用shutdown()方法狡忙,來關(guān)閉使用梳虽。