Android的線程和線程池

讀完開發(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)閉使用梳虽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市灾茁,隨后出現(xiàn)的幾起案子窜觉,更是在濱河造成了極大的恐慌,老刑警劉巖北专,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禀挫,死亡現(xiàn)場離奇詭異,居然都是意外死亡拓颓,警方通過查閱死者的電腦和手機(jī)语婴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來驶睦,“玉大人砰左,你說我怎么就攤上這事∩斗保” “怎么了菜职?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵青抛,是天一觀的道長旗闽。 經(jīng)常有香客問我,道長蜜另,這世上最難降的妖魔是什么适室? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮举瑰,結(jié)果婚禮上捣辆,老公的妹妹穿的比我還像新娘。我一直安慰自己此迅,他們只是感情好汽畴,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著耸序,像睡著了一般忍些。 火紅的嫁衣襯著肌膚如雪衍腥。 梳的紋絲不亂的頭發(fā)上两曼,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機(jī)與錄音搭独,去河邊找鬼搅窿。 笑死嘁酿,一個(gè)胖子當(dāng)著我的面吹牛隙券,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播闹司,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼娱仔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了游桩?” 一聲冷哼從身側(cè)響起拟枚,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎众弓,沒想到半個(gè)月后恩溅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谓娃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年脚乡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滨达。...
    茶點(diǎn)故事閱讀 40,427評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奶稠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捡遍,到底是詐尸還是另有隱情锌订,我是刑警寧澤,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布画株,位于F島的核電站辆飘,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏谓传。R本人自食惡果不足惜蜈项,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望续挟。 院中可真熱鬧紧卒,春花似錦、人聲如沸诗祸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽直颅。三九已至博个,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間际乘,已是汗流浹背坡倔。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人罪塔。 一個(gè)月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓投蝉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親征堪。 傳聞我的和親對象是個(gè)殘疾皇子瘩缆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評論 2 359

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

  • 一、概述 Android 的線程分主線程和子線程佃蚜,主線程主要處理界面相關(guān)的事情庸娱,而子線程往往用于執(zhí)行耗時(shí)操作。An...
    innovatorCL閱讀 312評論 0 0
  • 前段時(shí)間遇到這樣一個(gè)問題谐算,有人問微信朋友圈的上傳圖片的功能怎么做才能讓用戶的等待時(shí)間較短熟尉,比如說一下上傳9張圖片,...
    加油碼農(nóng)閱讀 1,204評論 0 2
  • Android中線程分為主線程和子線程,主線程主要處理和界面相關(guān)的事情洲脂,子線程則往往用于執(zhí)行耗時(shí)操作斤儿。 1.1、A...
    Ryan_Hoo閱讀 319評論 0 0
  • 從用途上來說恐锦,線程分為主線程和子線程往果,主線程主要處理和界面相關(guān)的事情,子線程則往往用于執(zhí)行耗時(shí)操作一铅。 除了Thre...
    小柏不是大白閱讀 632評論 0 3
  • 加入刻意訓(xùn)練營一周的時(shí)間陕贮,最大的感受就是心里很清楚每天有一個(gè)任務(wù),而且非常清楚一定要完成潘飘,不認(rèn)識你就出局肮之。 隨著時(shí)...
    含章可貞_8927閱讀 165評論 0 0