AsyncTask与多任务

问题由来

     之前看到一篇博文,说AsyncTask不适合运行多任务, 多个任务不会异步执行, 当时只是印象里记住了一下也不确定, 今天把代码看了看, 把原因写出来。

 

问题的代码演示

 

 1 public class AsyncTaskDemo  extends AsyncTask<String, Integer, String>{
 2     private final static String TAG = "AsyncTaskTest";
 3 
 4     @Override
 5     protected String doInBackground(String... params) {
 6         Log.v(TAG, params[0] + "=================doInBackground===================PID = " + Thread.currentThread().getId());
 7 
 8         return params[0];
 9     }  
10 
11 
12 }

 

1 // 一个按钮的onclick函数    
2 public void test(View view) {
3         Log.v("AsyncTaskTest", "CPU_COUNT = " + Runtime.getRuntime().availableProcessors());
4 
5         new AsyncTaskDemo().execute("Hello1");
6         new AsyncTaskDemo().execute("Hello2");
7         new AsyncTaskDemo().execute("Hello3");
8         new AsyncTaskDemo().execute("Hello4");
9     }
//logcat里打印出来的结果

12-11 16:07:34.865    1979-1979/com.sabo.helloworld V/AsyncTaskTest﹕ CPU_COUNT = 1
12-11 16:07:34.871    1979-2102/com.sabo.helloworld V/AsyncTaskTest﹕ Hello1=================doInBackground===================PID = 161
12-11 16:07:34.872    1979-2103/com.sabo.helloworld V/AsyncTaskTest﹕ Hello2=================doInBackground===================PID = 162
12-11 16:07:34.872    1979-2103/com.sabo.helloworld V/AsyncTaskTest﹕ Hello3=================doInBackground===================PID = 162
12-11 16:07:34.872    1979-2103/com.sabo.helloworld V/AsyncTaskTest﹕ Hello4=================doInBackground===================PID = 162

实验大致辅证了"AsyncTask不适合运行多任务"这个推断, 另一个有趣的结果是非异步执行的时候居然可能不是在一个线程里运行的【看我上面用红色标记的部分】。

 

分析:

 

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

 

    @MainThread
    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);// exec  --> sDefaultExecutor

        return this;
    }

如果熟悉Java的并发编程的话就知道sDefaultExecutor用于将要完成的任务交给内部已经实现的线程池去执行(有兴趣的话可以去看看Doug Lea写的那本《Java并发编程》)

public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

private static volatile Executor sDefaultExecutor = 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);
            }
        }
    }

这里的代码就能解释为什么多个AsyncTask一起执行时序列化执行而被异步的了, 

1         new AsyncTaskDemo().execute("Hello1"); //mActive == null
2         new AsyncTaskDemo().execute("Hello2"); //mActive != null
3         new AsyncTaskDemo().execute("Hello3"); //mActive != null
4         new AsyncTaskDemo().execute("Hello4"); //mActive != null

上面红色标记的代码可以看出,只有第一个任务直接调用scheduleNext()--->THREAD_POOL_EXECUTOR.execute(mActive), 线程池直接将任务交由线程去执行,而后面几个任务先被放入ArrayDeque<Runnable> mTasks, 没有交给任何线程去执行,

每个任务执行完之后又都要运行上面绿颜色标记的scheduleNext(), 从而依次序序列化执行任务。

 

上面提到的有趣的事情,既然AsyncTask是序列化执行任务的, 那么线程池里只要一个线程就能满足要求了啊, 为什么会有两个线程。

1     private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
2     private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
3     private static final int KEEP_ALIVE = 1;
4 
5     public static final Executor THREAD_POOL_EXECUTOR
6             = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
7                     TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

上面我把CPU_COUNT的值打印出来是1, 所以这里线程池的线程数就可能是[2, 3]了, 然而对于AsyncTask来说1就够了, 多余1的线程其实是没有什么帮助的。

 

P.S.

:-)第一次写博客, 加上功力又有限, 欢迎大家指正canbin.zhang#qq.com

     

转载于:https://www.cnblogs.com/sabo/p/5040685.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值