線程和線程池

線程

在java中實(shí)現(xiàn)線程的方式:

  1. 繼承Thread類
  2. 實(shí)現(xiàn)Runable接口点楼。

main方法其實(shí)也是一個(gè)線程糖儡。
在java中,每次程序運(yùn)行至少啟動(dòng)2個(gè)線程贷币。一個(gè)是main線程击胜,一個(gè)是垃圾收集線程。

  • 對(duì)比
    實(shí)現(xiàn)Runnable接口比繼承Thread類所具有的優(yōu)勢(shì):
    1):適合多個(gè)相同的程序代碼的線程去處理同一個(gè)資源
    2):可以避免java中的單繼承的限制
    3):增加程序的健壯性役纹,代碼可以被多個(gè)線程共享潜的,代碼和數(shù)據(jù)獨(dú)立

  • yield()方法

    Thread.yield()方法作用是:暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程字管。
    yield()應(yīng)該做的是讓當(dāng)前運(yùn)行線程回到可運(yùn)行狀態(tài),以允許具有相同優(yōu)先級(jí)的其他線程獲得運(yùn)行機(jī)會(huì)信不。因此嘲叔,使用yield()的目的是讓相同優(yōu)先級(jí)的線程之間能適當(dāng)?shù)妮嗈D(zhuǎn)執(zhí)行。但是抽活,實(shí)際中無(wú)法保證yield()達(dá)到讓步目的硫戈,因?yàn)樽尣降木€程還有可能被線程調(diào)度程序再次選中。

結(jié)論:yield()從未導(dǎo)致線程轉(zhuǎn)到等待/睡眠/阻塞狀態(tài)下硕。在大多數(shù)情況下丁逝,yield()將導(dǎo)致線程從運(yùn)行狀態(tài)轉(zhuǎn)到可運(yùn)行狀態(tài),但有可能沒有效果梭姓。

  • join()方法
    保證當(dāng)前線程停止執(zhí)行霜幼,直到該線程所加入的線程完成為止,當(dāng)前線程方可繼續(xù)執(zhí)行誉尖。然而罪既,如果它加入的線程沒有存活,則當(dāng)前線程不需要停止铡恕。

AsyncTask

  • 內(nèi)部由兩個(gè)線程池和一個(gè)Handler組成琢感。
    1. SerialExecutor:用于任務(wù)的排隊(duì),一次執(zhí)行一個(gè)探熔。
    2. ThreadPoolExecutor:用于真正的執(zhí)行任務(wù)驹针。
    3. InternalHandler:用于發(fā)送結(jié)果數(shù)據(jù)從子線程到主線程。
  • 執(zhí)行流程:
    構(gòu)造方法中實(shí)例化WorkerRunnable和FutureTask對(duì)象诀艰。
    WorkerRunnable將Params參數(shù)封裝柬甥,并將自己封裝在FutureTask中饮六,一旦FutureTask執(zhí)行run方法時(shí),會(huì)去調(diào)用WorkRunnable的call方法并返回Result值暗甥。call方法中就執(zhí)行了AsyncTask的doInBackground方法喜滨。并調(diào)用postResult方法將結(jié)果發(fā)送出去。
mWorker = new WorkerRunnable<Params, Result>() {
    public Result call() throws Exception {
        mTaskInvoked.set(true);

        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        //noinspection unchecked
        Result result = doInBackground(mParams);
        Binder.flushPendingCommands();
        return postResult(result);
    }
};

  private Result postResult(Result result) {
        @SuppressWarnings("unchecked")
        Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
                new AsyncTaskResult<Result>(this, result));
        message.sendToTarget();
        return result;
  }

那么FutureTask是什么時(shí)候執(zhí)行的撤防?
FutureTask充當(dāng)了Runnable的作用虽风,交給SerialExecutor的execute方法執(zhí)行。FutureTask是一個(gè)并發(fā)類寄月,可以中途取消的用于異步計(jì)算的類辜膝。

SerialExecutor的execute方法首先把FutureTask插入到mTasks任務(wù)隊(duì)列中,如果沒有活動(dòng)的任務(wù)漾肮,則執(zhí)行下一個(gè)厂抖。當(dāng)一個(gè)任務(wù)執(zhí)行完成,會(huì)繼續(xù)調(diào)用scheduleNext方法執(zhí)行下一個(gè)克懊,直到所有任務(wù)都被執(zhí)行忱辅。

THREAD_POOL_EXECUTOR.execute(mActive);才是真正執(zhí)行任務(wù)的方法。使用的是ThreadPoolExecutor線程池谭溉。

private static class SerialExecutor implements Executor {
  final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
  Runnable mActive;

  public synchronized void execute(final Runnable r) {
      //將FutureTask插入到mTasks任務(wù)隊(duì)列中
      mTasks.offer(new Runnable() {
          public void run() {
              try {
                  // 執(zhí)行FutureTask的run方法墙懂,進(jìn)而執(zhí)行call方法
                  r.run();
              } finally {
                  // 串行執(zhí)行下一個(gè)任務(wù)
                  scheduleNext();
              }
          }
      });
      //沒有正在活動(dòng)的任務(wù),執(zhí)行下一個(gè)AsyncTask扮念。
      if (mActive == null) {
          scheduleNext();
      }
  }

  protected synchronized void scheduleNext() {
      if ((mActive = mTasks.poll()) != null) {
          THREAD_POOL_EXECUTOR.execute(mActive);
      }
  }
}
  • 注意:
  1. AsyncTask對(duì)象必須在主線程中創(chuàng)建
  2. execute必須在主線程中調(diào)用
  3. 一個(gè)AsyncTask只能調(diào)用一次execute方法损搬,

HandlerThread

繼承了Thread類,本質(zhì)還是線程柜与。但是可以直接使用Handler的Thread巧勤。在run方法中通過(guò)Looper.prepare創(chuàng)建消息隊(duì)列,并開啟消息循環(huán)弄匕。使得可以再此線程中創(chuàng)建Handler颅悉。

由于loop開啟了無(wú)限循環(huán),因此可以通過(guò)quit或者quitSafely方法終止線程執(zhí)行粘茄。

同時(shí)签舞,它還解決了一個(gè)Looper與Handler的同步問(wèn)題∑獍辏可以保證根據(jù)當(dāng)前線程的Looper創(chuàng)建Handler時(shí)儒搭,Looper對(duì)象的獲取不為空。
參考《深入理解Android 卷I》159頁(yè)

    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason is isAlive() returns false, this method will return null. If this thread 
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

典型應(yīng)用場(chǎng)景就是在IntentService中芙贫。

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

IntentService

一個(gè)可以處理異步請(qǐng)求的Service.服務(wù)開啟后搂鲫,工作線程會(huì)依次處理每個(gè)Intent,任務(wù)執(zhí)行完畢后會(huì)自動(dòng)關(guān)閉磺平。

相對(duì)于線程而言魂仍,IntentService更適合執(zhí)行一些高優(yōu)先級(jí)的后臺(tái)任務(wù)拐辽。

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

線程池

  • 優(yōu)點(diǎn)
  1. 重用線程池中的線程,避免因?yàn)榫€程的創(chuàng)建和銷毀帶來(lái)的性能開銷擦酌。
  2. 有效控制線程的最大并發(fā)數(shù)俱诸,避免因大量的線程之間互相搶占系統(tǒng)資源而導(dǎo)致的阻塞 。
  3. 能夠?qū)€程進(jìn)行簡(jiǎn)單的管理赊舶,并提供定時(shí)執(zhí)行和執(zhí)行循環(huán)間隔執(zhí)行等功能
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {  }
  • 變量

    • corePoolSize: 核心線程數(shù)
    • maximumPoolSize: 最大線程數(shù)
    • workQueue:任務(wù)隊(duì)列睁搭,提交的Runnable對(duì)象存儲(chǔ)在這里。
    • keepAliveTime: 非核心線程存活時(shí)間
    • unit:keepAliveTime的時(shí)間單位笼平。
    • threadFactory:為線程池提供新線程的工廠园骆。
    • handler:異常處理策略。
  • 規(guī)則

  1. 如果此時(shí)線程池中的數(shù)量小于corePoolSize寓调,即使線程池中的線程都處于空閑狀態(tài)锌唾,也要?jiǎng)?chuàng)建新的線程來(lái)處理被添加的任務(wù)。
  2. 如果此時(shí)線程池中的數(shù)量等于 corePoolSize夺英,但是緩沖隊(duì)列 workQueue未滿晌涕,那么任務(wù)被放入緩沖隊(duì)列。
  3. 如果此時(shí)線程池中的數(shù)量大于corePoolSize痛悯,緩沖隊(duì)列workQueue滿渐排,并且線程池中的數(shù)量小于maximumPoolSize,建新的線程來(lái)處理被添加的任務(wù)灸蟆。
  4. 如果此時(shí)線程池中的數(shù)量大于corePoolSize,緩沖隊(duì)列workQueue滿亲族,并且線程池中的數(shù)量等于maximumPoolSize炒考,那么通過(guò) handler所指定的策略來(lái)處理此任務(wù)。

參閱:
Java多線程學(xué)習(xí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末霎迫,一起剝皮案震驚了整個(gè)濱河市斋枢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌知给,老刑警劉巖瓤帚,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涩赢,居然都是意外死亡戈次,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門筒扒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)怯邪,“玉大人,你說(shuō)我怎么就攤上這事花墩⌒” “怎么了澄步?”我有些...
    開封第一講書人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)和泌。 經(jīng)常有香客問(wèn)我村缸,道長(zhǎng),這世上最難降的妖魔是什么武氓? 我笑而不...
    開封第一講書人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任梯皿,我火速辦了婚禮,結(jié)果婚禮上聋丝,老公的妹妹穿的比我還像新娘索烹。我一直安慰自己,他們只是感情好弱睦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開白布百姓。 她就那樣靜靜地躺著,像睡著了一般况木。 火紅的嫁衣襯著肌膚如雪垒拢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,365評(píng)論 1 302
  • 那天火惊,我揣著相機(jī)與錄音求类,去河邊找鬼。 笑死屹耐,一個(gè)胖子當(dāng)著我的面吹牛尸疆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惶岭,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼寿弱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了按灶?” 一聲冷哼從身側(cè)響起症革,我...
    開封第一講書人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸯旁,沒想到半個(gè)月后噪矛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铺罢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年艇挨,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片韭赘。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡雷袋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情楷怒,我是刑警寧澤蛋勺,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站鸠删,受9級(jí)特大地震影響抱完,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜刃泡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一巧娱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烘贴,春花似錦禁添、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至锻离,卻和暖如春铺峭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背汽纠。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工卫键, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人虱朵。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓莉炉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親碴犬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子呢袱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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

  • Android中的線程 線程,在Android中是非常重要的翅敌,主線程處理UI界面,子線程處理耗時(shí)操作惕蹄。如果在主線程...
    shenhuniurou閱讀 755評(píng)論 0 3
  • 從用途上來(lái)說(shuō)蚯涮,線程分為主線程和子線程,主線程主要處理和界面相關(guān)的事情卖陵,子線程則往往用于執(zhí)行耗時(shí)操作遭顶。 除了Thre...
    小柏不是大白閱讀 629評(píng)論 0 3
  • 線程 操作系統(tǒng)調(diào)度最小單元,不可能無(wú)限制產(chǎn)生(受限的系統(tǒng)資源)泪蔫,線程創(chuàng)建與銷毀有相應(yīng)的開銷棒旗。當(dāng)系統(tǒng)中存在大量線程的...
    墨染書閱讀 646評(píng)論 1 5
  • 11.1 主線程和子線程 Android中的主線程主要處理和界面相關(guān)的事情,而子線程則往往用于執(zhí)行耗時(shí)操作,如網(wǎng)絡(luò)...
    Xerrard閱讀 375評(píng)論 0 0
  • 一張稚嫩的臉龐 變得越發(fā)成熟 曾經(jīng)的懵懂無(wú)知 今朝回憶 笑顏綻放 兒時(shí)的兩小無(wú)猜 青春的互生愛戀 好奇變成探索 快...
    未來(lái)之光閱讀 152評(píng)論 0 0