中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Android的線程和線程池

2018-07-20    來源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬Linux鏡像隨意使用

(1) 在Java中默認(rèn)情況下一個(gè)進(jìn)程只有一個(gè)線程,也就是主線程,其他線程都是子線程,也叫工作線程。Android中的主線程主要處理和界面相關(guān)的事情,而子線程則往往用于執(zhí)行耗時(shí)操作。線程的創(chuàng)建和銷毀的開銷較大,所以如果一個(gè)進(jìn)程要頻繁地創(chuàng)建和銷毀線程的話,都會(huì)采用線程池的方式。

(2) 在Android中除了Thread,還有HandlerThread、AsyncTask以及IntentService等也都扮演著線程的角色,只是它們具有不同的特性和使用場(chǎng)景。AsyncTask封裝了線程池和Handler,它主要是為了方便開發(fā)者在子線程中更新UI。HandlerThread是一種具有消息循環(huán)的線程,在它的內(nèi)部可以使用Handler。IntentService是一個(gè)服務(wù),它內(nèi)部采用HandlerThread來執(zhí)行任務(wù),當(dāng)任務(wù)執(zhí)行完畢后就會(huì)自動(dòng)退出。因?yàn)樗欠⻊?wù)的緣故,所以和后臺(tái)線程相比,它比較不容易被系統(tǒng)殺死。

(3). 從Android 3.0開始,系統(tǒng)要求網(wǎng)絡(luò)訪問必須在子線程中進(jìn)行,否則網(wǎng)絡(luò)訪問將會(huì)失敗并拋出NetworkOnMainThreadException這個(gè)異常,這樣做是為了避免主線程由于被耗時(shí)操作所阻塞從而出現(xiàn)ANR現(xiàn)象。

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

AsyncTask

AsyncTask是一個(gè)抽象泛型類,它提供了Params、Progress、Result三個(gè)泛型參數(shù),如果task確實(shí)不需要傳遞具體的參數(shù),那么都可以設(shè)置為Void。下面是它的四個(gè)核心方法,其中doInBackground不是在主線程執(zhí)行的。

onPreExecute、doInBackground、onProgressUpdate、onPostResult

注意事項(xiàng):

  • AsyncTask必須在主線程中加載
  • 必須在誅仙城中創(chuàng)建
  • execute必須在UI線程調(diào)用
  • 一個(gè)AsyncTask對(duì)象只能執(zhí)行一次,即只能調(diào)用一次execute方法
  • 在Android1.6的時(shí)候線程池是并行任務(wù),在Android3.0為了避免并發(fā)錯(cuò)誤采用串行執(zhí)行任務(wù)。但是我們?nèi)匀豢梢杂眠^executeOnExecutor方法并行執(zhí)行任務(wù)。

HandlerThread

它繼承了Thread,是一種可以使用Handler的Thread.他的實(shí)現(xiàn)也很簡(jiǎn)單,就是在run方法中通過Looper。prepare來創(chuàng)建消息隊(duì)列,并通過Looper.loop來開啟消息循環(huán),這樣在使用的時(shí)候就可以在HandlerThread中創(chuàng)建Handler了。

@Override
public void run() {
    mTid = Process.myTid();
    Looper.prepare();
    synchronized (this) {
        mLooper = Looper.myLooper();
        notifyAll();
    }
    Process.setThreadPriority(mPriority);
    onLooperPrepared();
    Looper.loop();
    mTid = -1;
}

HandlerThread在內(nèi)部創(chuàng)建了消息隊(duì)列,外界需要通過Handler的消息方式開通知它執(zhí)行一個(gè)具體的任務(wù),它的一個(gè)具體實(shí)現(xiàn)是IntentService。當(dāng)我們不需要使用Handler的時(shí)候可以通過quit獲取quitSafelt方法終結(jié)線程的執(zhí)行。

IntentService

繼承了Service是一個(gè)抽象類,必須創(chuàng)建它的子類才可以使用它,IntentService可以執(zhí)行后臺(tái)耗時(shí)任務(wù),當(dāng)任務(wù)執(zhí)行完畢之后會(huì)自動(dòng)停止,因?yàn)樗欠⻊?wù),所以他的優(yōu)先級(jí)比普通的線程高,比較適合執(zhí)行一些高優(yōu)先級(jí)的后臺(tái)任務(wù)。

Android中的線程池

Android里面,耗時(shí)的網(wǎng)絡(luò)操作,都會(huì)開子線程,在程序里面直接開過多的線程會(huì)消耗過多的資源,在眾多的開源框架中也總能看到線程池的蹤影,所以線程池是必須要會(huì)把握的一個(gè)知識(shí)點(diǎn);

線程池的優(yōu)點(diǎn):

  • 重用線程池中的線程,避免頻繁創(chuàng)建和銷毀帶來的性能開銷
  • 可以有效控制線程池中的最大并發(fā)數(shù),避免大量線程之間互相搶占系統(tǒng)資源導(dǎo)致阻塞
  • 可以對(duì)線程進(jìn)行簡(jiǎn)單管理。

線程運(yùn)行機(jī)制

  • 開啟線程過多,會(huì)消耗 cpu資源
  • 單核cpu,同一時(shí)刻只能處理一個(gè)線程,多核cpu同一時(shí)刻可以處理多個(gè)線程
  • 操作系統(tǒng)為每個(gè)運(yùn)行線程安排一定的CPU時(shí)間—- 時(shí)間片 ,系統(tǒng)通過一種循環(huán)的方式為線程提供時(shí)間片,線程在自己的時(shí)間內(nèi)運(yùn)行,因?yàn)闀r(shí)間相當(dāng)短,多個(gè)線程頻繁地發(fā)生切換,因此給用戶的感覺就是好像多個(gè)線程同時(shí)運(yùn)行一樣,但是如果計(jì)算機(jī)有多個(gè)CPU,線程就能真正意義上的同時(shí)運(yùn)行了.

線程池的作用

  • 線程池是預(yù)先創(chuàng)建線程的一種技術(shù)。線程池在還沒有任務(wù)到來之前,創(chuàng)建一定數(shù)量的線程,放入空閑隊(duì)列中,然后對(duì)這些資源進(jìn)行復(fù)用。 減少頻繁的創(chuàng)建和銷毀對(duì)象。
  • 頻繁創(chuàng)建和銷毀線程耗資源,耗時(shí)間
  • 因?yàn)橛械木程執(zhí)行時(shí)間比創(chuàng)建和銷毀一個(gè)線程的時(shí)間還短

線程池涉及的類

  • Executor:Java里面線程池的頂級(jí)接口。
  • ExecutorService:真正的線程池接口。
  • ScheduledExecutorService:能和Timer/TimerTask類似,解決那些需要任務(wù)重復(fù)執(zhí)行的問題。
  • ThreadPoolExecutor(重點(diǎn)):ExecutorService的默認(rèn)實(shí)現(xiàn)。
  • ScheduledThreadPoolExecutor:繼承ThreadPoolExecutor的ScheduledExecutorService接口實(shí)現(xiàn),周期性任務(wù)調(diào)度的類實(shí)現(xiàn)。
  • Executors:可以一行代碼創(chuàng)建一些常見的線程池。

Executors介紹(把握使用,把握常見線程池)

Executors:jdk1.5之后的一個(gè)新類, 提供了一些靜態(tài)方法,幫助我們方便的生成一些常用的線程池 ,ThreadPoolExecutor是Executors類的底層實(shí)現(xiàn)

1.newSingleThreadExecutor

創(chuàng)建一個(gè)單線程的線程池。這個(gè)線程池只有一個(gè)線程在工作,也就是相當(dāng)于單線程串行執(zhí)行>所有任務(wù)。如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來替代它。此線程池>保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。

2.newFixedThreadPool

創(chuàng)建固定大小的線程池。每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程,直到線程達(dá)到線程池的最大大小。線程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程。

3.newCachedThreadPool

創(chuàng)建一個(gè)可緩存的線程池。如果線程池的大小超過了處理任務(wù)所需要的線程,

那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時(shí),此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會(huì)對(duì)線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。

4.newScheduledThreadPool

創(chuàng)建一個(gè)大小無限的線程池。此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。

ThreadPoolExecutor介紹

//構(gòu)造方法
public ThreadPoolExecutor(int corePoolSize,//核心池的大小
                              int maximumPoolSize,//線程池最大線程數(shù)
                              long keepAliveTime,//保持時(shí)間
                              TimeUnit unit,//時(shí)間單位
                              BlockingQueue<Runnable> workQueue,//任務(wù)隊(duì)列
                              ThreadFactory threadFactory,//線程工廠
                              RejectedExecutionHandler handler) //異常的捕捉器

構(gòu)造相關(guān)參數(shù)解釋

  • corePoolSize: 核心池的大小 ,這個(gè)參數(shù)跟后面講述的線程池的實(shí)現(xiàn)原理有非常大的關(guān)系。在創(chuàng)建了線程池后,默認(rèn)情況下,線程池中并沒有任何線程,而是等待有任務(wù)到來才創(chuàng)建線程去執(zhí)行任務(wù),除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個(gè)方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思,即在沒有任務(wù)到來之前就創(chuàng)建corePoolSize個(gè)線程或者一個(gè)線程。默認(rèn)情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為0,當(dāng)有任務(wù)來之后,就會(huì)創(chuàng)建一個(gè)線程去執(zhí)行任務(wù),當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后,就會(huì)把到達(dá)的任務(wù)放到緩存隊(duì)列當(dāng)中;
  • maximumPoolSize: ’線程池最大線程數(shù) ,
    這個(gè)參數(shù)也是一個(gè)非常重要的參數(shù),它表示在線程池中最多能創(chuàng)建多少個(gè)線程;
  • keepAliveTime: 表示線程沒有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會(huì)終止 。默認(rèn)情況下,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí),keepAliveTime才會(huì)起作用,直到線程池中的線程數(shù)不大于corePoolSize,即當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí),如果一個(gè)線程空閑的時(shí)間達(dá)到keepAliveTime,則會(huì)終止,直到線程池中的線程數(shù)不超過corePoolSize。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時(shí),keepAliveTime參數(shù)也會(huì)起作用,直到線程池中的線程數(shù)為0;
  • unit:參數(shù)keepAliveTime的 時(shí)間單位 ,有7種取值

    TimeUnit.DAYS;               //天
    TimeUnit.HOURS;             //小時(shí)
    TimeUnit.MINUTES;           //分鐘
    TimeUnit.SECONDS;           //秒
    TimeUnit.MILLISECONDS;      //毫秒
    TimeUnit.MICROSECONDS;      //微妙
    TimeUnit.NANOSECONDS;       //納秒
  • workQueue : 任務(wù)隊(duì)列 ,是一個(gè)阻塞隊(duì)列,用來存儲(chǔ)等待執(zhí)行的任務(wù),這個(gè)參數(shù)的選擇也很重要,會(huì)對(duì)線程池的運(yùn)行過程產(chǎn)生重大影響,參考BlockingQueue

    ArrayBlockingQueue
    LinkedBlockingQueue
    SynchronousQueue
  • threadFactory : 線程工廠 ,如何去創(chuàng)建線程的

  • handler : 任務(wù)隊(duì)列添加 異常的捕捉器 ,參考 RejectedExecutionHandler

    ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。 
    ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。 
    ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
    ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)

基礎(chǔ)API的介紹

  • isShutdown() : 判斷線程池是否關(guān)閉
  • isTerminated() : 判斷線程池中任務(wù)是否執(zhí)行完成
  • shutdown() : 調(diào)用后不再接收新任務(wù),如果里面有任務(wù),就執(zhí)行完
  • shutdownNow() : 調(diào)用后不再接受新任務(wù),如果有等待任務(wù),移出隊(duì)列;有正在執(zhí)行的,嘗試停止之
  • submit() : 提交執(zhí)行任務(wù)
  • execute() : 執(zhí)行任務(wù)

任務(wù)提交給線程池之后的處理策略

  1. 如果當(dāng)前線程池中的線程數(shù)目小于corePoolSize,則每來一個(gè)任務(wù),就會(huì)創(chuàng)建執(zhí)行這個(gè)任務(wù);
  2. 如果當(dāng)前線程池中的線程數(shù)目>=corePoolSize,則每來一個(gè)任務(wù),會(huì)嘗試將其添加到任務(wù)緩存隊(duì)列當(dāng)中
    1. 若添加成功,則該任務(wù)會(huì)等待空閑線程將其取出去執(zhí)行;
    2. 若添加失敗(一般來說是任務(wù)緩存隊(duì)列已滿,針對(duì)的是有界隊(duì)列),則會(huì)嘗試創(chuàng)建新的線程去執(zhí)行這個(gè)任務(wù);
  3. 如果當(dāng)前線程池中的線程數(shù)目達(dá)到maximumPoolSize,則會(huì)采取任務(wù)拒絕策略進(jìn)行處理;
  4. 如果線程池中的線程數(shù)量大于 corePoolSize時(shí),如果某線程空閑時(shí)間超過keepAliveTime,線程將被終止,直至線程池中的線程數(shù)目不大于corePoolSize;如果允許為核心池中的線程設(shè)置存活時(shí)間,那么核心池中的線程空閑時(shí)間超過keepAliveTime,線程也會(huì)被終止。

任務(wù)提交給線程池之后的處理策略_比喻

假如有一個(gè)工廠,工廠里面有10( corePoolSize )個(gè)工人,每個(gè)工人同時(shí)只能做一件任務(wù)。

因此只要當(dāng)10個(gè)工人中有工人是空閑的, 來了任務(wù)就分配 給空閑的工人做;

當(dāng)10個(gè)工人都有任務(wù)在做時(shí),如果還來了任務(wù),就把任務(wù)進(jìn)行排隊(duì)等待( 任務(wù)隊(duì)列 );

如果說新任務(wù)數(shù)目增長的速度遠(yuǎn)遠(yuǎn)大于工人做任務(wù)的速度,那么此時(shí)工廠主管可能會(huì)想補(bǔ)救措施,比如重新招4個(gè)臨時(shí)工人( 創(chuàng)建新線程 )進(jìn)來;然后就將任務(wù)也分配給這4個(gè)臨時(shí)工人做;

如果說著14個(gè)工人做任務(wù)的速度還是不夠,此時(shí)工廠主管可能就要考慮不再接收新的任務(wù)或者拋棄前面的一些任務(wù)了( 拒絕執(zhí)行 )。

當(dāng)這14個(gè)工人當(dāng)中有人空閑時(shí),而且空閑超過一定時(shí)間( 空閑時(shí)間 ),新任務(wù)增長的速度又比較緩慢,工廠主管可能就考慮辭掉4個(gè)臨時(shí)工了,只保持原來的10個(gè)工人,畢竟請(qǐng)額外的工人是要花錢的

阻塞隊(duì)列的介紹(BlockingQueue)

阻塞隊(duì)列,如果BlockingQueue是空的,從BlockingQueue取東西的操作將會(huì)被阻斷進(jìn)入等待狀態(tài),直到BlockingQueue進(jìn)了東西才會(huì)被喚醒,同樣,如果BlockingQueue是滿的,任何試圖往里存東西的操作也會(huì)被阻斷進(jìn)入等待狀態(tài),直到BlockingQueue里有空間時(shí)才會(huì)被喚醒繼續(xù)操作。

  1. 基礎(chǔ)API介紹

    • 往隊(duì)列中加元素的方法

      • add(E) : 非阻塞方法, 把元素加到BlockingQueue里,如果BlockingQueue可以容納,則返回true,否則拋出異常。
      • offer(E) : 非阻塞, 表示如果可能的話,將元素加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則返回false。
      • put(E):阻塞方法, 把元素加到BlockingQueue里,如果BlockingQueue沒有空間,則調(diào)用此方法的線程被阻斷直到BlockingQueue里有空間再繼續(xù)。
    • 從隊(duì)列中取元素的方法

      • poll(time): 阻塞方法,取走BlockingQueue里排在首位的元素,若不能立即取出,則可以等time參數(shù)規(guī)定的時(shí)間,取不到時(shí)返回null。
      • take():取走BlockingQueue里排在首位的對(duì)象,若BlockingQueue為空,阻斷進(jìn)入等待狀態(tài)直到BlockingQueue有新的對(duì)象被加入為止。
  2. 子類介紹

    • ArrayBlockingQueue(有界隊(duì)列) : FIFO 隊(duì)列,規(guī)定大小的BlockingQueue,其構(gòu)造函數(shù)必須帶一個(gè)int參數(shù)來指明其大小

    • LinkedBlockingQueue(無界隊(duì)列) :FIFO 隊(duì)列,大小不定的BlockingQueue,若其構(gòu)造函數(shù)帶一個(gè)規(guī)定大小的參數(shù),生成的BlockingQueue有大小限制,若不帶大小參數(shù),所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定。

    • PriorityBlockingQueue :優(yōu)先級(jí)隊(duì)列, 類似于LinkedBlockingQueue,但隊(duì)列中元素非 FIFO, 依據(jù)對(duì)象的自然排序順序或者是構(gòu)造函數(shù)所帶的Comparator決定的順序

    • SynchronousQueue(直接提交策略) : 交替隊(duì)列, 隊(duì)列中操作時(shí)必須是先放進(jìn)去,接著取出來 ,交替著去處理元素的添加和移除,這是一個(gè)很有意思的阻塞隊(duì)列,其中每個(gè)插入操作必須等待另一個(gè)線程的移除操作,同樣任何一個(gè)移除操作都等待另一個(gè)線程的插入操作。因此此隊(duì)列內(nèi)部其 實(shí)沒有任何一個(gè)元素,或者說容量是0,嚴(yán)格說并不是一種容器。由于隊(duì)列沒有容量,因此不能調(diào)用peek操作,因?yàn)橹挥幸瞥貢r(shí)才有元素。

 

來自:https://imuhao.github.io/2016/08/19/Thread-Executors/

標(biāo)簽: 代碼 開發(fā)者 網(wǎng)絡(luò)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:簡(jiǎn)析.NET Core 以及與 .NET Framework的關(guān)系

下一篇:C# 之 Hashtable 與 Dictionary