AsyncTask作为android原生的处理异步任务的方案,问题很多,比如不允许多个任务同时运行,关于这一点,网上有很多说法,早期的说法是AsyncTask最初被引入的时候只支持一个任务同时运行,后期增加到了5个,我今天特意验证了一下看看:
private void start(View view){for (int i = 0; i < 100; i++) {new Task().execute();}}class Task extends AsyncTask<Void,Void,Void>{@Overrideprotected Void voids) {try {int times = 100;for (int i = 0; i < times; i++) {System.out.println("thread"+Thread.currentThread()+i+"");Thread.sleep(10);}} catch (Exception e) {}return null;}}
在for循环中开启了一百个异步任务,每个任务打印从0到99,每次打印sleep10毫秒,发现结果出乎意料:
03-29 16:36:09.323 appmarket I/System.out: threadThread[AsyncTask #4,5,main]0
03-29 16:36:09.334 appmarket I/System.out: threadThread[AsyncTask #4,5,main]1
03-29 16:36:09.344 appmarket I/System.out: threadThread[AsyncTask #4,5,main]2
03-29 16:36:09.354 appmarket I/System.out: threadThread[AsyncTask #4,5,main]3
03-29 16:36:09.365 appmarket I/System.out: threadThread[AsyncTask #4,5,main]4
03-29 16:36:09.375 appmarket I/System.out: threadThread[AsyncTask #4,5,main]5
03-29 16:36:09.385 appmarket I/System.out: threadThread[AsyncTask #4,5,main]6
03-29 16:36:09.396 appmarket I/System.out: threadThread[AsyncTask #4,5,main]7
03-29 16:36:09.406 appmarket I/System.out: threadThread[AsyncTask #4,5,main]8
03-29 16:36:09.416 appmarket I/System.out: threadThread[AsyncTask #4,5,main]9
03-29 16:36:09.426 appmarket I/System.out: threadThread[AsyncTask #4,5,main]10
03-29 16:36:09.437 appmarket I/System.out: threadThread[AsyncTask #4,5,main]11
03-29 16:36:09.447 appmarket I/System.out: threadThread[AsyncTask #4,5,main]12
03-29 16:36:09.457 appmarket I/System.out: threadThread[AsyncTask #4,5,main]13
03-29 16:36:09.468 appmarket I/System.out: threadThread[AsyncTask #4,5,main]14
03-29 16:36:09.478 appmarket I/System.out: threadThread[AsyncTask #4,5,main]15
03-29 16:36:09.488 appmarket I/System.out: threadThread[AsyncTask #4,5,main]16
03-29 16:36:09.499 appmarket I/System.out: threadThread[AsyncTask #4,5,main]17
03-29 16:36:09.509 appmarket I/System.out: threadThread[AsyncTask #4,5,main]18
03-29 16:36:09.520 appmarket I/System.out: threadThread[AsyncTask #4,5,main]19
03-29 16:36:09.531 appmarket I/System.out: threadThread[AsyncTask #4,5,main]20
03-29 16:36:09.541 appmarket I/System.out: threadThread[AsyncTask #4,5,main]21
03-29 16:36:09.552 appmarket I/System.out: threadThread[AsyncTask #4,5,main]22
03-29 16:36:09.562 appmarket I/System.out: threadThread[AsyncTask #4,5,main]23
03-29 16:36:09.573 appmarket I/System.out: threadThread[AsyncTask #4,5,main]24
03-29 16:36:09.583 appmarket I/System.out: threadThread[AsyncTask #4,5,main]25
03-29 16:36:09.594 appmarket I/System.out: threadThread[AsyncTask #4,5,main]26
03-29 16:36:09.606 appmarket I/System.out: threadThread[AsyncTask #4,5,main]27
03-29 16:36:09.617 appmarket I/System.out: threadThread[AsyncTask #4,5,main]28
03-29 16:36:09.627 appmarket I/System.out: threadThread[AsyncTask #4,5,main]29
03-29 16:36:09.638 appmarket I/System.out: threadThread[AsyncTask #4,5,main]30
03-29 16:36:09.649 appmarket I/System.out: threadThread[AsyncTask #4,5,main]31
03-29 16:36:09.659 appmarket I/System.out: threadThread[AsyncTask #4,5,main]32
03-29 16:36:09.670 appmarket I/System.out: threadThread[AsyncTask #4,5,main]33
03-29 16:36:09.681 appmarket I/System.out: threadThread[AsyncTask #4,5,main]34
03-29 16:36:09.692 appmarket I/System.out: threadThread[AsyncTask #4,5,main]35
03-29 16:36:09.703 appmarket I/System.out: threadThread[AsyncTask #4,5,main]36
03-29 16:36:09.713 appmarket I/System.out: threadThread[AsyncTask #4,5,main]37
03-29 16:36:09.724 appmarket I/System.out: threadThread[AsyncTask #4,5,main]38
03-29 16:36:09.734 appmarket I/System.out: threadThread[AsyncTask #4,5,main]39
03-29 16:36:09.745 appmarket I/System.out: threadThread[AsyncTask #4,5,main]40
03-29 16:36:09.755 appmarket I/System.out: threadThread[AsyncTask #4,5,main]41
03-29 16:36:09.766 appmarket I/System.out: threadThread[AsyncTask #4,5,main]42
03-29 16:36:09.776 appmarket I/System.out: threadThread[AsyncTask #4,5,main]43
03-29 16:36:09.787 appmarket I/System.out: threadThread[AsyncTask #4,5,main]44
03-29 16:36:09.797 appmarket I/System.out: threadThread[AsyncTask #4,5,main]45
03-29 16:36:09.808 appmarket I/System.out: threadThread[AsyncTask #4,5,main]46
03-29 16:36:09.818 appmarket I/System.out: threadThread[AsyncTask #4,5,main]47
03-29 16:36:09.828 appmarket I/System.out: threadThread[AsyncTask #4,5,main]48
03-29 16:36:09.839 appmarket I/System.out: threadThread[AsyncTask #4,5,main]49
03-29 16:36:09.849 appmarket I/System.out: threadThread[AsyncTask #4,5,main]50
03-29 16:36:09.860 appmarket I/System.out: threadThread[AsyncTask #4,5,main]51
03-29 16:36:09.870 appmarket I/System.out: threadThread[AsyncTask #4,5,main]52
03-29 16:36:09.880 appmarket I/System.out: threadThread[AsyncTask #4,5,main]53
03-29 16:36:09.891 appmarket I/System.out: threadThread[AsyncTask #4,5,main]54
03-29 16:36:09.902 appmarket I/System.out: threadThread[AsyncTask #4,5,main]55
03-29 16:36:09.913 appmarket I/System.out: threadThread[AsyncTask #4,5,main]56
03-29 16:36:09.923 appmarket I/System.out: threadThread[AsyncTask #4,5,main]57
03-29 16:36:09.934 appmarket I/System.out: threadThread[AsyncTask #4,5,main]58
03-29 16:36:09.944 appmarket I/System.out: threadThread[AsyncTask #4,5,main]59
03-29 16:36:09.955 appmarket I/System.out: threadThread[AsyncTask #4,5,main]60
03-29 16:36:09.965 appmarket I/System.out: threadThread[AsyncTask #4,5,main]61
03-29 16:36:09.976 appmarket I/System.out: threadThread[AsyncTask #4,5,main]62
03-29 16:36:09.986 appmarket I/System.out: threadThread[AsyncTask #4,5,main]63
03-29 16:36:09.997 appmarket I/System.out: threadThread[AsyncTask #4,5,main]64
03-29 16:36:10.007 appmarket I/System.out: threadThread[AsyncTask #4,5,main]65
03-29 16:36:10.018 appmarket I/System.out: threadThread[AsyncTask #4,5,main]66
03-29 16:36:10.028 appmarket I/System.out: threadThread[AsyncTask #4,5,main]67
03-29 16:36:10.038 appmarket I/System.out: threadThread[AsyncTask #4,5,main]68
03-29 16:36:10.049 appmarket I/System.out: threadThread[AsyncTask #4,5,main]69
03-29 16:36:10.059 appmarket I/System.out: threadThread[AsyncTask #4,5,main]70
03-29 16:36:10.070 appmarket I/System.out: threadThread[AsyncTask #4,5,main]71
03-29 16:36:10.080 appmarket I/System.out: threadThread[AsyncTask #4,5,main]72
03-29 16:36:10.091 appmarket I/System.out: threadThread[AsyncTask #4,5,main]73
03-29 16:36:10.101 appmarket I/System.out: threadThread[AsyncTask #4,5,main]74
03-29 16:36:10.112 appmarket I/System.out: threadThread[AsyncTask #4,5,main]75
03-29 16:36:10.122 appmarket I/System.out: threadThread[AsyncTask #4,5,main]76
03-29 16:36:10.133 appmarket I/System.out: threadThread[AsyncTask #4,5,main]77
03-29 16:36:10.143 appmarket I/System.out: threadThread[AsyncTask #4,5,main]78
03-29 16:36:10.153 appmarket I/System.out: threadThread[AsyncTask #4,5,main]79
03-29 16:36:10.164 appmarket I/System.out: threadThread[AsyncTask #4,5,main]80
03-29 16:36:10.174 appmarket I/System.out: threadThread[AsyncTask #4,5,main]81
03-29 16:36:10.184 appmarket I/System.out: threadThread[AsyncTask #4,5,main]82
03-29 16:36:10.195 appmarket I/System.out: threadThread[AsyncTask #4,5,main]83
03-29 16:36:10.206 appmarket I/System.out: threadThread[AsyncTask #4,5,main]84
03-29 16:36:10.216 appmarket I/System.out: threadThread[AsyncTask #4,5,main]85
03-29 16:36:10.227 appmarket I/System.out: threadThread[AsyncTask #4,5,main]86
03-29 16:36:10.237 appmarket I/System.out: threadThread[AsyncTask #4,5,main]87
03-29 16:36:10.248 appmarket I/System.out: threadThread[AsyncTask #4,5,main]88
03-29 16:36:10.258 appmarket I/System.out: threadThread[AsyncTask #4,5,main]89
03-29 16:36:10.269 appmarket I/System.out: threadThread[AsyncTask #4,5,main]90
03-29 16:36:10.279 appmarket I/System.out: threadThread[AsyncTask #4,5,main]91
03-29 16:36:10.290 appmarket I/System.out: threadThread[AsyncTask #4,5,main]92
03-29 16:36:10.301 appmarket I/System.out: threadThread[AsyncTask #4,5,main]93
03-29 16:36:10.311 appmarket I/System.out: threadThread[AsyncTask #4,5,main]94
03-29 16:36:10.322 appmarket I/System.out: threadThread[AsyncTask #4,5,main]95
03-29 16:36:10.332 appmarket I/System.out: threadThread[AsyncTask #4,5,main]96
03-29 16:36:10.343 appmarket I/System.out: threadThread[AsyncTask #4,5,main]97
03-29 16:36:10.353 appmarket I/System.out: threadThread[AsyncTask #4,5,main]98
03-29 16:36:10.364 appmarket I/System.out: threadThread[AsyncTask #4,5,main]99
03-29 16:36:10.375 appmarket I/System.out: threadThread[AsyncTask #4,5,main]0
03-29 16:36:10.386 appmarket I/System.out: threadThread[AsyncTask #4,5,main]1
03-29 16:36:10.396 appmarket I/System.out: threadThread[AsyncTask #4,5,main]2
03-29 16:36:10.407 appmarket I/System.out: threadThread[AsyncTask #4,5,main]3
03-29 16:36:10.417 appmarket I/System.out: threadThread[AsyncTask #4,5,main]4
03-29 16:36:10.428 appmarket I/System.out: threadThread[AsyncTask #4,5,main]5
03-29 16:36:10.438 appmarket I/System.out: threadThread[AsyncTask #4,5,main]6
03-29 16:36:10.448 appmarket I/System.out: threadThread[AsyncTask #4,5,main]7
03-29 16:36:10.459 appmarket I/System.out: threadThread[AsyncTask #4,5,main]8
03-29 16:36:10.469 appmarket I/System.out: threadThread[AsyncTask #4,5,main]9
03-29 16:36:10.480 appmarket I/System.out: threadThread[AsyncTask #4,5,main]10
03-29 16:36:10.491 appmarket I/System.out: threadThread[AsyncTask #4,5,main]11
03-29 16:36:10.502 appmarket I/System.out: threadThread[AsyncTask #4,5,main]12
03-29 16:36:10.512 appmarket I/System.out: threadThread[AsyncTask #4,5,main]13
03-29 16:36:10.523 appmarket I/System.out: threadThread[AsyncTask #4,5,main]14
03-29 16:36:10.534 appmarket I/System.out: threadThread[AsyncTask #4,5,main]15
03-29 16:36:10.544 appmarket I/System.out: threadThread[AsyncTask #4,5,main]16
03-29 16:36:10.555 appmarket I/System.out: threadThread[AsyncTask #4,5,main]17
03-29 16:36:10.565 appmarket I/System.out: threadThread[AsyncTask #4,5,main]18
......
在一个AsyncTask执行完成之前,另一个任务不会开始,也就是目前仍然,AsyncTask只能同时执行一个后台线程
接下来看源码
我们把AsyncTask的几个方法作为源码阅读的入口
execute 开始执行
cancel 取消执行
execute
//@MainThread 只能在主线程中开启
@MainThreadpublic final AsyncTask<Params, Progress, Result> params) {return executeOnExecutor(sDefaultExecutor, params);}
我们知道,AsyncTask是通过线程池,Handler,Runnable集合来处理的,sDefaultExecutor继承自Executor,用来处理异步任务
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_ute(mActive);}}}
executeOnExecutor
@MainThreadpublic final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor params) {//判断当前任务的状态,如果不是未开始执行,而是正在执行或者已经执行//完成就抛出异常,所以一个任务只能执行一次,这就是一个任务调用两次execute方法会报错的原因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,重写此方法可进行一些初始化操作onPreExecute();//将参数存入worker的数组中mWorker.mParams = params;//这个exec就是刚刚传入的那个线程池类sDefaultExecutor,//将mFuture传入,执行sDefaultExecutor的execute方法ute(mFuture);return this;}
这里看到了一个mFuture,这个mFuture是什么呢,它是在AsyncTask的构造方法中初始化的
public AsyncTask(@Nullable Looper callbackLooper) {mHandler = callbackLooper == null || callbackLooper == MainLooper()? getMainHandler(): new Handler(callbackLooper);mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {mTaskInvoked.set(true);Result result = null;try {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection uncheckedresult = doInBackground(mParams);Binder.flushPendingCommands();} catch (Throwable tr) {mCancelled.set(true);throw tr;} finally {postResult(result);}return result;}};mFuture = new FutureTask<Result>(mWorker) {@Overrideprotected void done() {try {postResultIfNotInvoked(get());} catch (InterruptedException e) {android.util.Log.w(LOG_TAG, e);} catch (ExecutionException e) {throw new RuntimeException("An error occurred while executing doInBackground()",e.getCause());} catch (CancellationException e) {postResultIfNotInvoked(null);}}};}
构造方法中初始化了一个Handler,用于接收子线程的消息,mWorker和mFuture是结合在一起使用的,mWorker是一种继承自Callable实现的线程,这种线程不同于Runnable和Thread,第一,可以有返回值,第二,可以抛出异常信息
private static abstract class WorkerRunnable<Params, Result> implements Callable<Result> {//之前传入的参数就是存在这里的Params[] mParams;}
FutureTask对Callable进行了一层包装,以保证这个线程可以被线程池执行ute(mFuture)线程池execute方法可以接受一个FutureTask对象
我们回到线程池Executor的execute方法中
private static class SerialExecutor implements Executor {final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();Runnable mActive;public synchronized void execute(final Runnable r) {//execute方法执行,将这个Runnable任务加入mTasksmTasks.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_ute(mActive);}}}
我们可以看到ArrayDeque是一个集合
public class ArrayDeque<E> extends AbstractCollection<E>
mTasks.offer是将这个任务加入了集合的尾部,相当于一个任务队列,
public boolean offer(E e) {return offerLast(e);}/*** Inserts the specified element at the end of this deque.** @param e the element to add* @return {@code true} (as specified by {@link Deque#offerLast})* @throws NullPointerException if the specified element is null*/public boolean offerLast(E e) {addLast(e);return true;}
看到这里我们已经接近了为什么AsyncTask只能同时执行一个任务这个问题的答案了,看这里
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
......private static class SerialExecutor implements Executor {final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();Runnable mActive;public synchronized void execute(final Runnable r) {//这里的操作只是将Runnable加入了mTasksmTasks.offer(new Runnable() {public void run() {try {r.run();} finally {scheduleNext();}}});//任务加入集合之后,执行这个方法,使用线程池//来执行集合中的runnable任务,THREAD_ute(mActive);if (mActive == null) {scheduleNext();}}protected synchronized void scheduleNext() {if ((mActive = mTasks.poll()) != null) {THREAD_ute(mActive);}}}
SerialExecutor是一个静态类,那么一旦初始化之后就会一直存在了,所有的AysyncTask共享这一个Executor,在第一个任务加入线程队列之后,取出第一个task开始执行第一个任务,并且给mActive附了值,此时mActive已经不再满足mActive==null的判断条件,也就是,在这个任务执行完成之前,如果有新的任务过来被加入任务队列,那么由于mActive==null的条件不成立,scheduleNext方法没法执行,这个任务就不会马上被执行,而是等待上一个任务完成之后再次调用scheduleNext开启下一个任务
当第一个Runnable中的异步任务执行完成的时候,会再执行scheduleNext()方法,从线程队列中取出下一个任务开始执行,所以说AsyncTask的任务执行顺序就是加入线程队列的前后顺序,到这里,最初的问题解决了,AsyncTask的确是一次只能同时执行一个任务
大概有人看到这里会觉得疑惑,对于这句话”当第一个Runnable中的异步任务执行完成的时候,会再执行scheduleNext()方法“中的Runnable中的异步任务指的是什么觉得不解,如果刚才的流程还记得的话,你会知道这个Runnable中的异步任务其实就是ute(mFuture)传过来的FutureTask中包装的Callable,FutureTask也是最终实现了Runnable接口,所以r.run()中的r就是这个FutureTask。那么既然是异步任务,为什么要说当他执行完成的时候才会执行scheduleNext方法呢,按常理讲,应该是同时进行的,这里就涉及到了Callable线程的一种特性
Callable线程运行过程中,会阻塞当前线程,直到执行完成获得执行结果
这也是为什么将Runnable往线程队列中加的时候,要在这个Callable线程的外边再加一个Runnable,为什么不直接把这个Callable加入队列中,因为Callable有这个特性,导致他执行的时候会阻塞当前线程,那么如果直接加入集合,执行的时候直接执行这个Callable,那么就会导致主线程被阻塞,因为当前还是主线程,所以必须在Runnable中执行这个Callable
所以当他运行的时候,当前线程被阻塞,那么
finally {scheduleNext();
}
不会被立即执行,而是等待他执行完成,一个任务执行完成之后,调用scheduleNext执行下一个任务
这时候我们再回到WorkerRunnable中,这里就是每一个任务执行的地方
mWorker = new WorkerRunnable<Params, Result>() {public Result call() throws Exception {mTaskInvoked.set(true);Result result = null;try {Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);//noinspection unchecked//回调doInBackground方法,执行我们的异步任务result = doInBackground(mParams);Binder.flushPendingCommands();} catch (Throwable tr) {mCancelled.set(true);throw tr;} finally {postResult(result);}return result;}};
当任务执行完成后,执行finally中的postResult方法,发送消息到Handler主线程
private Result postResult(Result result) {@SuppressWarnings("unchecked")Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,new AsyncTaskResult<Result>(this, result));message.sendToTarget();return result;}
private static class InternalHandler extends Handler {public InternalHandler(Looper looper) {super(looper);}@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})@Overridepublic void handleMessage(Message msg) {AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;switch (msg.what) {case MESSAGE_POST_RESULT:// There is only one resultresult.mTask.finish(result.mData[0]);break;case MESSAGE_POST_PROGRESS:ProgressUpdate(result.mData);break;}}}
调用AsyncTask的finish方法,并传递任务执行结果
private void finish(Result result) {if (isCancelled()) {onCancelled(result);} else {//回调onPostExecute,一个任务完成onPostExecute(result);}mStatus = Status.FINISHED;}
下面我们再从cancel方法这个切入点去看源码
public final boolean cancel(boolean mayInterruptIfRunning) {mCancelled.set(true);return mFuture.cancel(mayInterruptIfRunning);}
调用的是FutureTask的cancel方法
public boolean cancel(boolean mayInterruptIfRunning) {if (!(state == NEW &&UpareAndSwapInt(this, STATE, NEW,mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))return false;try { // in case call to interrupt throws exceptionif (mayInterruptIfRunning) {try {Thread t = runner;if (t != null)t.interrupt();} finally { // final stateU.putOrderedInt(this, STATE, INTERRUPTED);}}} finally {finishCompletion();}return true;}
finishCompletion
private void finishCompletion() {// assert state > COMPLETING;for (WaitNode q; (q = waiters) != null;) {if (UpareAndSwapObject(this, WAITERS, q, null)) {for (;;) {Thread t = q.thread;if (t != null) {q.thread = null;LockSupport.unpark(t);}WaitNode next = q.next;if (next == null) = null; // unlink to help gcq = next;}break;}}done();callable = null; // to reduce footprint}
最终还是走到done方法中
本文发布于:2024-01-31 21:12:51,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170670677331388.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |