Asynctask SerialExecutor不是串行执行的

时间:2013-12-02 04:00:26

标签: android android-asynctask

我创建了以下2个Asynctasks

public class MyAsynctaskWithDelay extends AsyncTask<String,Void,Void> {

    @Override
    protected Void doInBackground(String... arg0) {
        // TODO Auto-generated method stub
        System.out.println(arg0[0] + "before sleeping of AsyctaskWithDelay..");
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(arg0[0] + "after sleeping of AsyctaskWithDelay..");
        //System.out.println(arg0[0]);
        return null;

    }

}

public class MyAsynctaskWithNoDelayLoop extends AsyncTask<String,Void,Void> {

    @Override
    protected Void doInBackground(String... arg0) {
        // TODO Auto-generated method stub
        System.out.println(arg0[0] + " The task with no delay...");
        //System.out.println(arg0[0]);
        return null;

    }
}

然后在主要活动中我做了如下:

        MyAsynctaskWithDelay asynctask1 = new MyAsynctaskWithDelay();
        MyAsynctaskWithDelay asynctask2 = new MyAsynctaskWithDelay();
        MyAsynctaskWithNoDelayLoop asynctask3 = new MyAsynctaskWithNoDelayLoop();
        MyAsynctaskWithNoDelayLoop asynctask4 = new MyAsynctaskWithNoDelayLoop();


        asynctask1.execute("Asynctask 1");
        asynctask2.execute("Asynctask 2");
        asynctask3.execute("Asynctask 3");
        asynctask4.execute("Asynctask 4");

因此,根据SerialExecutor的定义,任务应该按照调用execute方法的顺序执行,后台任务不应该被抢占。

但是,我已运行此应用程序并获得以下结果。

12-02 09:18:20.526: I/System.out(402): Asynctask 1before sleeping of AsyctaskWithDelay..
12-02 09:18:20.576: I/System.out(402): Asynctask 2before sleeping of AsyctaskWithDelay..
12-02 09:18:20.586: I/System.out(402): Asynctask 3 The task with no delay...
12-02 09:18:20.586: I/System.out(402): Asynctask 4 The task with no delay...
12-02 09:18:30.582: I/System.out(402): Asynctask 1after sleeping of AsyctaskWithDelay..
12-02 09:18:30.703: I/System.out(402): Asynctask 2after sleeping of AsyctaskWithDelay..

很明显前两个任务在doinbackground方法中被抢占了,这显然不是预期的。

请澄清我的疑虑,以便我可以回答我自己关于Asynctask Serialexecutor如何运作的问题。

如果我们深入研究Android的Serial Executor类的源代码,我们会找到

 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);
            }
        }
    }

如果我们将执行函数的以下部分视为

 mTasks.offer(new Runnable() {
                    public void run() {
                        try {
                            r.run();
                        } finally {
                            scheduleNext();
                        }
                    }
                });

我们将知道,每次调用执行函数时,它都会创建一个新线程,并在该线程内执行后台任务。这意味着任何长时间运行的后台任务都可以被另一个不同的Asynctask实例的执行后台任务抢占。那么为什么它被称为Serial Executor。

1 个答案:

答案 0 :(得分:0)

AsyncTask是线程的简单替代品。所以线程(无论是否是串行执行程序)你不应该依赖于它们的执行顺序。如果你只需要将它们串行化,那么你必须自己处理它们。