Asynctask的解析

在我剛剛接觸AsyncTask的時候我也很鬱悶其中是怎麼進行串行與並行的?
在安卓的1.6以前其實本來是採用的串行執行任務,在1.6-3.0之間爲了併發訪問,安卓修改了能執行並行的,後來由於可以執行並行大家在很多地方都使用的導致線程創創建過多,所以在3.0以後又改爲串行
    在不同的地方new一個AsyncTask還能使用同一個線程池,後來查看源碼我們可知道

查看源碼可以知道Executor SERIAL_EXECUTOR是靜態的隨着類的的加載而加載,另外handler也是跟進程綁定的。
所以當我們執行下面的代碼的時候是共享一個線程池和handler的

 new MyAsyncTask("AsyncTask#1").execute("");  
        new MyAsyncTask("AsyncTask#2").execute("");  
        new MyAsyncTask("AsyncTask#3").execute("");  
        new MyAsyncTask("AsyncTask#4").execute("");  
        new MyAsyncTask("AsyncTask#5").execute("");  

每次new AyncTask()都是創建一個任務,假如通知五個對象執行execute,那就給mTasks塞進去(offer)五個任務,然後走scheduleNext()方法,在這個 方法中mActive = mTasks.poll(),取出最前面那個執行,run方法走完了以後,走finaly{},這裏面在取隊列最前面的任務,以此往復。。。實現了串行。。。

public AsyncTask() {
        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);
            }
        };

然後將這個任務封裝成進 mFuture = new FutureTask(mWorker) ;
每次拿着對象調用exectu();

 public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params) {
        if (mStatus != Status.PENDING) {
            switch (mStatus) {
                case RUNNING:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task is already running.");
                case FINISHED:
                    throw new IllegalStateException("Cannot execute task:"
                            + " the task has already been executed "
                            + "(a task can be executed only once)");
            }
        }

        mStatus = Status.RUNNING;

        onPreExecute();

        mWorker.mParams = params;
        exec.execute(mFuture);

        return this;
    }

然後這個任務就被扔給線程池SerialExecutor的實例。

 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();//這裏創建管理run的線程池

    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    private static final InternalHandler sHandler = new InternalHandler();
    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//這裏創建去執行任務的線程池。


----------

`我們查看SerialExecutor的源碼``
 private static class SerialExecutor implements Executor {
        final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
        Runnable mActive;

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

通過上面這個對任務runnable進行一次封裝到mTasks集合裏面, 第一次進去mActive==null然後執行了scheduleNext(),在這個方法裏面我們把封裝好的集合裏的第一個任務賦值給mActive,這時候判斷不爲null,就去執行第二個線程池裏的execute(run)方法scheduleNext(),然後把這個任務run方法結束的時候有個finaly{}在這個裏面我們會再次調用,當這時候假如有別的任務加進來的話,這時候的又往mTasks後面(addLast)添加了任務,判斷集合有任務的話在執行這個任務,這樣就形成了一個串行的實現
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}

看串行的原理

 AsyncTask asyncTask=new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] params) {
                return null;
            }
        };

 asyncTask.execute(new Runnable() {
            @Override
            public void run() {

            }
        });
 public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

    private static final int MESSAGE_POST_RESULT = 0x1;
    private static final int MESSAGE_POST_PROGRESS = 0x2;

    private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;//這裏創建管理run的線程池
    private static InternalHandler sHandler;

    private final WorkerRunnable<Params, Result> mWorker;
    private final FutureTask<Result> mFuture;

    private volatile Status mStatus = Status.PENDING;

    private final AtomicBoolean mCancelled = new AtomicBoolean();
    private final AtomicBoolean mTaskInvoked = new AtomicBoolean();

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

        public synchronized void execute(final Runnable r) {
            mTasks.offer(new Runnable() {
                public void run() {
                    try {
                        r.run();
                    } finally {
                        scheduleNext();
                    }
                }
            });
            if (mActive == null) {
                scheduleNext();
            }
        }

        protected synchronized void scheduleNext() {
            if ((mActive = mTasks.poll()) != null) {
                THREAD_POOL_EXECUTOR.execute(mActive);
            }
        }
    }

execute方法走的是這個方法,sDefaultExecutor默認的話使用的是sDefaultExecutor線程池。。。 而sDefaultExecutor是由SerialExecutor串行線程池new出來的,所以默認的情況下AsyncTask是串行的

SERIAL_EXECUTOR = new SerialExecutor(),
sDefaultExecutor = SERIAL_EXECUTOR;

  @MainThread
    public final AsyncTask<Params, Progress, Result> execute(Params... params) {
        return executeOnExecutor(sDefaultExecutor, params);
    }

那麼我們有沒有辦法AsyncTask用並行的呢?
答案肯定是有的
怎麼做?
AsyncTask爲我們提供了一個Api,asyncTask.executeOnExecutor,其實這個也是asyncTask.execute(), 最終調用的方法。
這裏面第一個參數就是我們自定義的線程池就可以實現了並行。。。


asyncTask.executeOnExecutor(Executor exec,
            Params... params)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章