Android線程和線程池


image.png

主線程與子線程

  1. 主線程:主線程主要處理UI交互纠脾,需要在任何時(shí)候都有較高的響應(yīng)速度亿傅,否則界面會(huì)產(chǎn)生卡頓。主線程中不能執(zhí)行耗時(shí)任務(wù)淤年,否則會(huì)出現(xiàn)ANR钧敞。主要作用是運(yùn)行四大組件,處理它們和用戶的交互
  2. 子線程:也叫工作線程麸粮,除主線程以外的線程都叫子線程溉苛。主要用來處理耗時(shí)任務(wù),如網(wǎng)絡(luò)請求弄诲、I/O愚战。

Android中的線程形態(tài)

Android中除了傳統(tǒng)的Thread之外,還包含了AsyncTask威根、HandlerThread以及IntentService凤巨,這三者底層實(shí)現(xiàn)也是Thread,但它們有特殊的形態(tài)和各自的優(yōu)缺點(diǎn)洛搀。

  1. AsyncTask
  • 一種輕量級(jí)的異步任務(wù)類敢茁,可以在線程池中執(zhí)行后臺(tái)任務(wù),然后把進(jìn)度和結(jié)果傳遞給主線程留美,并在主線程中更新UI彰檬。AsyncTask內(nèi)部封裝了Thread和Handler。
  • AsyncTask是一個(gè)抽象泛型類谎砾,提供了三個(gè)參數(shù)Params逢倍、Progress和Result,Params表示參數(shù)景图,Progress表示后臺(tái)任務(wù)執(zhí)行的進(jìn)度類型较雕,Result表示返回結(jié)果的類型。
public abstract class AsyncTask<Params, Progress, Result> 
  • 四個(gè)核心方法:onPreExecute=異步任務(wù)執(zhí)行之前調(diào)用挚币,可做一些準(zhǔn)備工作(主線程)亮蒋、doInBackground=用于執(zhí)行異步任務(wù)(線程池),在此方法中調(diào)用publishProgress可以更新任務(wù)進(jìn)度onProgressUpdate=后臺(tái)任務(wù)進(jìn)度發(fā)生改變會(huì)調(diào)用(主線程)妆毕、onPostExecute=異步任務(wù)執(zhí)行完成之后慎玖,該方法被調(diào)用(主線程)
  • 除了上面的四個(gè)方法,AsyncTask還提供了onCancelled方法(主線程)笛粘,異步任務(wù)取消時(shí)趁怔,onCancelled會(huì)被調(diào)用湿硝,這個(gè)時(shí)候onPostExecute不會(huì)被調(diào)用。
  • AsyncTask使用過程中有幾個(gè)限制:AsyncTask必須在主線程中創(chuàng)建和加載润努,execute方法也要在主線程中調(diào)用关斜,execute方法只能調(diào)用一次,不然會(huì)報(bào)錯(cuò)任连。不要在程序中直接調(diào)用上面四個(gè)核心方法蚤吹。
  • version < Android1.6:串行執(zhí)行任務(wù),Android1.6 <= version < Android3.0:采用線程池并行執(zhí)行任務(wù)随抠,version >= Android3.0:線程池串行執(zhí)行任務(wù)裁着,不過仍可通過executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, xxx)指定并發(fā)線程池來并行執(zhí)行任務(wù)
  • AsyncTask原理分析:1拱她、AsyncTask的構(gòu)造方法中會(huì)初始化一個(gè)sHandler:InternalHandler對象二驰,還會(huì)初始化一個(gè)mWorker:WorkerRunnable對象(執(zhí)行doInBackgroud,并且把結(jié)果發(fā)送個(gè)sHandler)秉沼,還有會(huì)用mWorker初始化mFuture:FutureTask對象(可取消桶雀、可查詢?nèi)蝿?wù)是否完成,可獲取任務(wù)結(jié)果)唬复。2矗积、execute方法會(huì)默認(rèn)使用sDefaultExecute(串行線程池)來調(diào)用executeOnExecutor方法,這個(gè)方法中會(huì)調(diào)用onPreExecute敞咧,并且會(huì)把mFuture作為一個(gè)Runnable(任務(wù))插入線程池的隊(duì)列mTask棘捣。3、如果此時(shí)沒有active的AsyncTask任務(wù)休建,就會(huì)調(diào)用scheduleNext來執(zhí)行隊(duì)列中的下一個(gè)AsyncTask乍恐,直到所有任務(wù)被執(zhí)行完為止。4测砂、mFuture任務(wù)執(zhí)行完成后會(huì)發(fā)送消息給sHandler對象茵烈,sHandler處理消息時(shí)調(diào)用onPostExecute把結(jié)果傳遞給主線程處理
  1. HandlerThread
  • 繼承自Thread,可以使用Handler的Thread
  • 在run方法中通過Looper.prepare初始化Looper砌些,并且通過Looper.loop方法開啟消息循環(huán)呜投。這樣就允許在HandlerThread中使用Handler了。
  • 普通Thread在run方法中執(zhí)行耗時(shí)任務(wù)存璃。而HandlerThread在run中開啟消息循環(huán)宙彪,外界需要通過Handler發(fā)送消息通知HandlerThread執(zhí)行一個(gè)具體任務(wù)。
  • 由于HandlerThread方法中調(diào)用Looper.loop方法有巧,是一個(gè)死循環(huán),當(dāng)不需要再使用HandlerThread時(shí)悲没,通過quit或quitSafety方法終止線程執(zhí)行篮迎。
  1. IntentService
  • 是一種特殊的Service男图,繼承Service的抽象類,抽象方法是onHandleIntent甜橱。正常的Service運(yùn)行在主線程逊笆,所以不能執(zhí)行耗時(shí)任務(wù),而IntentService的任務(wù)是放在HandlerThread中執(zhí)行岂傲,因此可以執(zhí)行耗時(shí)任務(wù)难裆。并且IntentService是四大組件,所以相對于一般線程來說镊掖,不易被系統(tǒng)殺死乃戈。
  • 在onCreate方法中,創(chuàng)建一個(gè)HandlerThread線程亩进,然后用該線程的Looper構(gòu)造一個(gè)Handler(即該Handler是在HandlerThread線程中處理消息)症虑。
  • 每次啟動(dòng)IntentService(startService),它的onStartCommand方法會(huì)被調(diào)用归薛,onStartCommand會(huì)調(diào)用onStart方法谍憔,onStart方法中會(huì)把Intent作為消息參數(shù),發(fā)送一個(gè)msg給Handler處理主籍,而Handler處理中會(huì)調(diào)用onHandleIntent方法(運(yùn)行在在HandlerThread線程中)习贫。
  • Handler處理消息后還會(huì)調(diào)用stopSelf(msg.arg1)方法結(jié)束IntentService,如果目前只存在一個(gè)后臺(tái)任務(wù)千元,那么執(zhí)行完后stopSelf直接停止服務(wù)苫昌,如果有多個(gè)后臺(tái)任務(wù),那么當(dāng)onHandleIntent執(zhí)行完最后一個(gè)任務(wù)時(shí)诅炉,stopSelf才會(huì)停止服務(wù)蜡歹。
  • onHandleIntent執(zhí)行多個(gè)后臺(tái)任務(wù),是按照外界發(fā)起的順序一次執(zhí)行涕烧。

Android中的線程池

  1. 線程池的優(yōu)點(diǎn)
  • 可以復(fù)用線程池中的線程月而,減少創(chuàng)建和銷毀線程帶來的開銷
  • 有效控制線程池中最大并發(fā)數(shù),避免線程之間相互搶占資源導(dǎo)致阻塞現(xiàn)象
  • 對線程進(jìn)行管理议纯,提供定時(shí)和周期執(zhí)行功能
  1. ThreadPoolExecutor
    ThreadPoolExecutor的繼承關(guān)系如下:
Executor interface
ExecutorService interface
AbstractExecutorService abstract class
ThreadPoolExecutor class

構(gòu)造方法如下:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<Runnable> workQueue,
                            ThreadFactory threadFactory,
                            RejectedExecutionHandler handler) {
      if (corePoolSize < 0 ||
          maximumPoolSize <= 0 ||
          maximumPoolSize < corePoolSize ||
          keepAliveTime < 0)
          throw new IllegalArgumentException();
      if (workQueue == null || threadFactory == null || handler == null)
          throw new NullPointerException();
      this.corePoolSize = corePoolSize;
      this.maximumPoolSize = maximumPoolSize;
      this.workQueue = workQueue;
      this.keepAliveTime = unit.toNanos(keepAliveTime);
      this.threadFactory = threadFactory;
      this.handler = handler;
  }

構(gòu)造方法中的參數(shù)解釋:

  • corePoolSize:核心線程數(shù)父款,核心線程在線程池中能夠一直存活,及時(shí)處于閑置狀態(tài)瞻凤。除非把a(bǔ)llowCoreThreadTimeOut設(shè)置為true憨攒,那么當(dāng)核心線程閑置超過一定時(shí)間,就會(huì)被終止阀参。
  • maximumPoolSize:線程池能容納的最大線程數(shù)肝集,當(dāng)線程數(shù)達(dá)到這個(gè)值,后續(xù)的任務(wù)將會(huì)被阻塞蛛壳。
  • keepAliveTime:線程閑置超時(shí)時(shí)間杏瞻,正常情況下所刀,非核心線程閑置超過這個(gè)時(shí)間會(huì)被回收,當(dāng)設(shè)置了allowCoreThreadTimeOut捞挥,那么該參數(shù)對核心線程也生效浮创。
  • unit:keepAliveTime對應(yīng)的單位,TimeUnit中取值
  • workQueue:線程池中的任務(wù)隊(duì)列砌函,通過線程池的execute方法提交的Runnable都會(huì)存儲(chǔ)在此斩披。
  • threadFactory:線程工廠,為線程池提供創(chuàng)建線程的功能讹俊,是個(gè)接口垦沉,只有一個(gè)方法:Thread newThread(Runnable r)
  • handler:不常用參數(shù)劣像,是RejectedExecutionHandler類型乡话,當(dāng)線程池?zé)o法執(zhí)行新任務(wù)時(shí)(任務(wù)隊(duì)列已滿),這是會(huì)調(diào)用handler的rejectedExecution來通知調(diào)用者耳奕,默認(rèn)情況會(huì)拋出一個(gè)異常RejectedExecutionException绑青。

ThreadPoolExecutor執(zhí)行邏輯如下:

1. 線程池線程數(shù)量未達(dá)到核心線程數(shù),直接啟動(dòng)核心線程執(zhí)行任務(wù)
2. 如果達(dá)到或超過核心線程數(shù)屋群,會(huì)插到任務(wù)對隊(duì)列中排隊(duì)等待執(zhí)行
3. 任務(wù)隊(duì)列已滿闸婴,如果線程數(shù)量未達(dá)到最大線程數(shù),則會(huì)啟動(dòng)非核心線程執(zhí)行任務(wù)
4. 如果達(dá)到最大線程數(shù)芍躏,就會(huì)拒絕新任務(wù)邪乍,會(huì)調(diào)用RejectedExecutionHandler的rejectedExecution來通知調(diào)用者
  1. 線程池分類
    主要介紹四種常見的線程池,都直接或間接配置ThreadPoolExecutor實(shí)現(xiàn)自己的功能对竣。
  • FixedThreadPool:線程數(shù)量固定庇楞,都是核心線程,任務(wù)隊(duì)列無限大否纬。線程不會(huì)被回收吕晌,能夠快速響應(yīng)外界請求
  • CachedThreadPool:都是非核心線程,并且非核心線程數(shù)量無上限临燃,閑置超時(shí)時(shí)間為60秒睛驳,任務(wù)隊(duì)列為空集合,所有任務(wù)都能立刻執(zhí)行膜廊。所有線程處于閑置狀態(tài)時(shí)乏沸,就會(huì)出現(xiàn)線程池內(nèi)無線程的情況。
  • ScheduledThreadPool:核心線程固定爪瓜,非核心線程無上限蹬跃,主要用來執(zhí)行定時(shí)任務(wù)和周期任務(wù)。
  • SingleThreadExecutor:只有一個(gè)核心線程铆铆,所有任務(wù)在核心線程中順序執(zhí)行蝶缀,不需要處理線程同步問題辆苔。

總結(jié)

本文主要介紹了Android中線程存在形式,還有線程池的分類和使用扼劈。希望對大家有幫助。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末菲驴,一起剝皮案震驚了整個(gè)濱河市荐吵,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赊瞬,老刑警劉巖先煎,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異巧涧,居然都是意外死亡薯蝎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門谤绳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來占锯,“玉大人,你說我怎么就攤上這事缩筛∠裕” “怎么了?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵瞎抛,是天一觀的道長艺演。 經(jīng)常有香客問我,道長桐臊,這世上最難降的妖魔是什么胎撤? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮断凶,結(jié)果婚禮上伤提,老公的妹妹穿的比我還像新娘。我一直安慰自己懒浮,他們只是感情好飘弧,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著砚著,像睡著了一般次伶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上稽穆,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天冠王,我揣著相機(jī)與錄音,去河邊找鬼舌镶。 笑死柱彻,一個(gè)胖子當(dāng)著我的面吹牛豪娜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哟楷,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼瘤载,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了卖擅?” 一聲冷哼從身側(cè)響起鸣奔,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎惩阶,沒想到半個(gè)月后挎狸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡断楷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年锨匆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冬筒。...
    茶點(diǎn)故事閱讀 40,852評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡恐锣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出账千,到底是詐尸還是另有隱情侥蒙,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布匀奏,位于F島的核電站鞭衩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏娃善。R本人自食惡果不足惜论衍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望聚磺。 院中可真熱鬧坯台,春花似錦、人聲如沸瘫寝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽焕阿。三九已至咪啡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暮屡,已是汗流浹背撤摸。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人准夷。 一個(gè)月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓钥飞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親衫嵌。 傳聞我的和親對象是個(gè)殘疾皇子读宙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容