android源碼值A(chǔ)yncTask

寫在前記:

總結(jié):相對(duì)于AsyncTask 比較常用的地方是用于IO密集型的咱揍,cpu占用率不會(huì)很高的地方

AsyncTask是什么

  1. android sdk 封裝的一個(gè)異步任務(wù)方案
  2. 模板類
  3. 提供了異步線程與UI線程的通信方式

實(shí)現(xiàn)方式

AsyncTask.java

public abstract class AyncTask<Params, Progress, Result>{
    // 泛型的參數(shù)說明
    // 1. Param 對(duì)應(yīng)excute 中傳遞參數(shù)的類型
    // 2. Progress: 異步執(zhí)行過程中返回進(jìn)度值督暂, 例如下載進(jìn)度值的類型
    // 3. Result: 異步任務(wù)執(zhí)行完成后的參數(shù)類型颅悉,doBackInBackground(param ...)  參數(shù)類型
    
}   

先回顧一下并發(fā)的幾個(gè)接口
Callable, Runnable, Future, FutureTask
Callable && Runnable 兩者之間的區(qū)別是

  1. 在執(zhí)行任務(wù)后是否有返回值
  2. callable的返回值類型通過泛型的方式約定

public interface Runnable{
    void run();
}

// 與runnable的區(qū)別在于,有返回值
public interface Callable<V>{
    V call() throw Exception;
}

public interface ExecutorService{
    <T> Future<T> submit(Callable<T> task)
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable tasl);
}

// future作用耿导,可以監(jiān)控目標(biāo)線程調(diào)用call赎离,當(dāng)調(diào)用get()的時(shí)候业踏,當(dāng)前線程開始阻塞禽炬,知道
public interface Future<V>{
    bool cancel(bool mayInterruptIfRunning);
    bool isCanceled();
    V get();
    V get(long timeout, TimeUnit unit);
 }
 
public interface RunnableFuture<V> extends Runnable, Future<V>{
    void run();
}

// RunnableFuture的實(shí)現(xiàn)類
public class FutureTask<V> impletements RunnableFuture<V>{
        // 內(nèi)部維護(hù)了一個(gè)狀態(tài)機(jī)
        // 一共7中,只會(huì)出現(xiàn)4中狀態(tài)變化
        //情況1 NEW->COMPLETING->NORMAL
        //情況2 NEW->COMPLETING->EXCEPTIONAL
        //情況3 NEW->CANCELLED
        //情況4 NEW->INTERRUPTING->INTERRUPTED
        private static final int NEW          = 0;
        private static final int COMPLETING   = 1;
        private static final int NORMAL       = 2;
        private static final int EXCEPTIONAL  = 3;
        private static final int CANCELLED    = 4;
        private static final int INTERRUPTING = 5;
        private static final int INTERRUPTED  = 6;

    // 看get方法是如何實(shí)現(xiàn)阻塞的
    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            s = awaitDone(false, 0L);
            
        // 根據(jù)state返回結(jié)果或者拋出異常
        return report(s);
    }
    
    // 核心方法
    // 該方法實(shí)現(xiàn)了自旋
    // 具體實(shí)現(xiàn):
    1)若支持中斷勤家,判斷當(dāng)前線程是否中斷
        1.1)中斷腹尖,退出自旋,從WaitNode等待隊(duì)列中移除當(dāng)前節(jié)點(diǎn)
        1.2)繼續(xù)下一步
    2) 判斷當(dāng)前狀態(tài)是否完成伐脖,如完成[中斷热幔,或者正常完成或者取消]直接直接返回狀態(tài),并且將當(dāng)前的thread設(shè)置為null讼庇,否則進(jìn)入下一步
    3)如果當(dāng)前狀態(tài)是正在完成中绎巨,暫時(shí)讓出cpu時(shí)間片,將線程從運(yùn)行態(tài)轉(zhuǎn)到就緒態(tài)蠕啄,否則進(jìn)入下一步
    4) 構(gòu)造一個(gè)waitNode场勤, 插入到隊(duì)列中
    
    private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            if (Thread.interrupted()) {
                removeWaiter(q);
                throw new InterruptedException();
            }

            int s = state;
            if (s > COMPLETING) {
            //退出
                if (q != null)
                    q.thread = null;
                return s;
            }
            else if (s == COMPLETING) 
                // 讓出時(shí)間片
                Thread.yield();
            else if (q == null)
                q = new WaitNode();
            else if (!queued)
            // 將任務(wù)插入到隊(duì)列中
                queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                     q.next = waiters, q);
            else if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    removeWaiter(q);
                    return state;
                }
                LockSupport.parkNanos(this, nanos);
            }
            else
            // locksupport park 阻塞對(duì)象, 等待LockSupport.park的調(diào)用返回,可以看到這個(gè)方法在finishCompletion中調(diào)用
                LockSupport.park(this);
        }
    }
    
    // 該方法在前面2-6狀態(tài)切換中都會(huì)被調(diào)用歼跟,正常的邏輯是在run方法中set()方法調(diào)用
      private void finishCompletion() {
        for (WaitNode q; (q = waiters) != null;) {
            if (U.compareAndSwapObject(this, WAITERS, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        // 核心的地方和媳,這個(gè)地方會(huì)喚醒阻塞的對(duì)象
                        LockSupport.unpark(t);
                    }
                    
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }

        // 完成
        done();

        callable = null;        // to reduce footprint
    }
    public void run() {
        if (state != NEW ||
            !U.compareAndSwapObject(this, RUNNER, null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    // 異常狀態(tài)
                    setException(ex);
                }
                if (ran)
                    // 正常狀態(tài)
                    set(result);
            }
        }
    }
}

以上是在執(zhí)行g(shù)et方法被阻塞的原理
接下來看executor中的submit(Runnable)/submit(Callable) 如何返回 RunnableFuture<T>

class abstract class AbstractExecutorService implements ExecutorService{
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
}

// FutureTask 中是如何將runable 轉(zhuǎn)換成callable,通過適配器模式實(shí)現(xiàn)
public class Executors{
      public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }
}

static class RunnableAdapter<T> implements Callcable<T>{
      final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
}

基于上述引入一個(gè)非常重要的鎖 LockSupport

LockSupport 的使用說明

  1. LockSupport.unpark()
  2. LockSupport.park()

LockSupport 的unpark和park無先后順序, 對(duì)于unpark在線哈街,則park不會(huì)阻塞留瞳,會(huì)直接返回

接下來分析一下Executors.java中的幾類線程池

  1. 區(qū)別: 核心線程數(shù) & 最大線程數(shù) & 容器的大小

先給結(jié)論:1.當(dāng)前存活線程數(shù)小于核心線程數(shù),則新建線程執(zhí)行任務(wù)骚秦,2.當(dāng)前核心線程都在忙她倘,任務(wù)會(huì)放進(jìn)隊(duì)列中,

  1. 如果隊(duì)列溢出作箍,則新建線程硬梁,如果新建線程數(shù)大于最大線程數(shù),則reject

上代碼:

class ThreadPoolExecutor{
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        // 是一個(gè)原子操作的interger變量胞得,低29位存儲(chǔ)線程數(shù)量荧止,高三位存儲(chǔ)線程池的狀態(tài)
        int c = ctl.get();
        if (workerCountOf(c) < corePoolSize) {
            if (addWorker(command, true))
                return;
            c = ctl.get();
        }
        if (isRunning(c) && workQueue.offer(command)) {
            int recheck = ctl.get();
            if (! isRunning(recheck) && remove(command))
                reject(command);
            else if (workerCountOf(recheck) == 0)
                addWorker(null, false);
        }
        else if (!addWorker(command, false))
            reject(command);
    }
}

未完成待續(xù)...

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市懒震,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嗤详,老刑警劉巖个扰,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異葱色,居然都是意外死亡递宅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來办龄,“玉大人烘绽,你說我怎么就攤上這事±睿” “怎么了安接?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長英融。 經(jīng)常有香客問我盏檐,道長,這世上最難降的妖魔是什么驶悟? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任胡野,我火速辦了婚禮,結(jié)果婚禮上痕鳍,老公的妹妹穿的比我還像新娘硫豆。我一直安慰自己,他們只是感情好笼呆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布熊响。 她就那樣靜靜地躺著,像睡著了一般抄邀。 火紅的嫁衣襯著肌膚如雪耘眨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天境肾,我揣著相機(jī)與錄音剔难,去河邊找鬼。 笑死奥喻,一個(gè)胖子當(dāng)著我的面吹牛偶宫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播环鲤,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纯趋,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了冷离?” 一聲冷哼從身側(cè)響起吵冒,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎西剥,沒想到半個(gè)月后痹栖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞭空,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年揪阿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疗我。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡南捂,死狀恐怖吴裤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情溺健,我是刑警寧澤麦牺,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站矿瘦,受9級(jí)特大地震影響枕面,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜缚去,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一潮秘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧易结,春花似錦枕荞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鹦肿,卻和暖如春矗烛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背箩溃。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國打工瞭吃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涣旨。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓歪架,卻偏偏與公主長得像,于是被迫代替她去往敵國和親霹陡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子和蚪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

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