AsyncTask并发执行的深度剖析

1.说明

使用AsyncTask时发现一个奇怪的现象,即创建多个任务的时候,他是一个一个按顺序执行的,查资料之后发现:在1.5中初始引入的时候, AsyncTask 执行( AsyncTask.execute() )起来是顺序的,当同时执行多个 AsyncTask的时候,他们会按照顺序一个一个执行。前面一个执行完才会执行后面一个。这样当同时执行多个比较耗时的任务的时候 可能不是您期望的结果,具体情况就像是execute的task不会被立即执行,要等待前面的task执行完毕后才可以执行。
 
在android 1.6(Donut) 到 2.3.2(Gingerbread)中,AsyncTask的执行顺序修改为并行执行了。如果同时执行多个任务,则这些任务会并行执行。 当任务访问同一个资源的时候 会出现并发问题。
而在Android 3.0(Honeycomb)以后的版本中,AsyncTask又修改为了顺序执行,并且新添加了一个函数 executeOnExecutor(Executor),如果您需要并行执行,则只需要调用该函数,并把参数设置为并行执行即可。即创建一个单独的线程池(Executors.newCachedThreadPool())。或者最简单的方法法就是使用executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR),这样起码不用等到前面的都结束了再执行了。executeOnExecutor(AsyncTask.SERIAL_EXECUTOR)则与execute()是一样的。

2.源码剖析

1.最简单的情况:顺序执行(AsyncTask.SERIAL_EXECUTOR)

我们首先演示顺序执行的情况,演示代码如下:
	@Override
	public void onClick(View v) {
		try {
			for (int i = 0; i < 23; i++) {
			  new MultiThread(i).execute();
			  //new MultiThread(i).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
			  //new MultiThread(i).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	class MultiThread extends AsyncTask<Void, Void, Void> {
		private int id;
		public MultiThread(int id){
			this.id=id;
		}
		@Override
		protected void onPostExecute(Void result) {
			Log.i("AsyncTask", Thread.currentThread().getName()+id+"/"+new Date().getSeconds());
		}
		
		@Override
		protected Void doInBackground(Void... params) {
			android.os.SystemClock.sleep(1000);
			return null;
		}
	}
}
从结果我们可以看到AsyncTask是顺序执行的,每秒钟执行一条。从logcat中我们可以看到:
09-29 17:49:59.127: I/AsyncTask(18361): main0/59
09-29 17:50:00.133: I/AsyncTask(18361): main1/0
09-29 17:50:01.144: I/AsyncTask(18361): main2/1
09-29 17:50:02.145: I/AsyncTask(18361): main3/2
09-29 17:50:03.147: I/AsyncTask(18361): main4/3
09-29 17:50:04.147: I/AsyncTask(18361): main5/4
09-29 17:50:05.148: I/AsyncTask(18361): main6/5
09-29 17:50:06.148: I/AsyncTask(18361): main7/6
09-29 17:50:07.149: I/AsyncTask(18361): main8/7
09-29 17:50:08.150: I/AsyncTask(18361): main9/8
09-29 17:50:09.150: I/AsyncTask(18361): main10/9
09-29 17:50:10.151: I/AsyncTask(18361): main11/10
09-29 17:50:11.152: I/AsyncTask(18361): main12/11
09-29 17:50:12.153: I/AsyncTask(18361): main13/12
09-29 17:50:13.153: I/AsyncTask(18361): main14/13
09-29 17:50:14.154: I/AsyncTask(18361): main15/14
09-29 17:50:15.155: I/AsyncTask(18361): main16/15
09-29 17:50:16.156: I/AsyncTask(18361): main17/16
09-29 17:50:17.156: I/AsyncTask(18361): main18/17
09-29 17:50:18.157: I/AsyncTask(18361): main19/18
09-29 17:50:19.157: I/AsyncTask(18361): main20/19
09-29 17:50:20.158: I/AsyncTask(18361): main21/20
09-29 17:50:21.158: I/AsyncTask(18361): main22/21

2.并发执行(AsyncTask.THREAD_POOL_EXECUTOR)

首先我们看源码android.os.AsyncTask<Params, Progress, Result>,有几个关键的参数我们需要弄清楚。
    private static final String LOG_TAG = "AsyncTask";

    private static final int CORE_POOL_SIZE = 5;
    private static final int MAXIMUM_POOL_SIZE = 128;
    private static final int KEEP_ALIVE = 1;

    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
        private final AtomicInteger mCount = new AtomicInteger(1);

        public Thread newThread(Runnable r) {
            return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
        }
    };

    private static final BlockingQueue<Runnable> sPoolWorkQueue =
            new LinkedBlockingQueue<Runnable>(10);

    /**
     * An {@link Executor} that can be used to execute tasks in parallel.
     */
    public static final Executor THREAD_POOL_EXECUTOR
            = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
                    TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
A.    corePoolSize: 线程池维护线程的最少数量
B.    maximumPoolSize:线程池维护线程的最大数量
C.    keepAliveTime: 线程池维护线程所允许的空闲时间
D.    unit: 线程池维护线程所允许的空闲时间的单位
E.    workQueue: 线程池所使用的缓冲队列
F.    handler: 线程池对拒绝任务的处理策略
当一个任务通过asynct.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, 0)方法欲添加到线程池时:
如果此时线程池中的数量小于corePoolSize,该线程是一直处于活动状态的。
如果此时线程池中的数量等于 corePoolSize,但是缓冲队列 workQueue未满,那么任务被放入缓冲队列(大小为10)。
如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量小于maximumPoolSize,建新的线程来处理被添加的任务。
	@Override
	public void onClick(View v) {
		try {
			for (int i = 0; i < 23; i++) {
			 // new MultiThread(i).execute();
			  //new MultiThread(i).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
			  new MultiThread(i).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

	}
验证结果如下:

如果此时线程池中的数量大于corePoolSize,缓冲队列workQueue满,并且线程池中的数量等于maximumPoolSize,那么通过 handler所指定的策略来处理此任务。
也就是:处理任务的优先级为:
核心线程corePoolSize、任务队列workQueue、最大线程maximumPoolSize,如果三者都满了,使用handler处理被拒绝的任务。
THREAD_POOL_EXECUTOR如果添加的任务过多,没有及时处理的话,会导致程序崩溃,它的队列size是128;它的调度规则是核心池大小,队列大小,以及最大线程数和异常处理Handler来决定的。
		try {
			for (int i = 0; i < 250; i++) {
			 // new MultiThread(i).execute();
			  //new MultiThread(i).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
			  new MultiThread(i).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
执行结果如下:


就这么简单!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值