AsyncTask分析笔记

AsyncTask. execute(Params… params)
params这个参数就是入参。异步执行任务的时候需要用到的参数可以用这个params传入。在这个方法可以接受到传入的参数。protected String doInBackground(Params… params)

这个execute(Params… params)方法的源码:里面去调用一个executeOnExecutor(sDefauItExecutor,params);
public final AsyncTask<Params, Progress, Result> execute(Params… params) {
return executeOnExecutor(sDefaultExecutor, params);
}
看看sDefauItExecutor是个什么东西,AsyncTask里面有一句这样的代码。
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;

再看看SERIAL_EXECUTOR 是什么?它是一个SerialExecutor这个可以暂时不管
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();

回来看看executeOnExecutor(sDefaultExecutor, params);里面做了什么:
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params… params) {
//if语句里面做了一个异常的判断。如果正在运行的会抛出这个任务已经在运行。如果是运行结束的,再重新运行的话会抛出这个任务只能运行异常。 所以我们不能同时执行一个任务。
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。mWorker是一个WorkerRunnable它是实现了Callabler的接口。
mWorker.mParams = params;
//exec是我们传入的。上面SERIAL_EXECUTOR就是这个exec。 exec.execute(mFuture)(mFuture是一个FutureTask)。
exec.execute(mFuture);
return this;
}

从上面mWorker.mParams= params 和exec.execute(mFuture)可以猜到这里的线程创建方式是Callable+FutureTask+Thread的方式。这种创建方式的好处是,线程结束后可以得到一个返回值结果。

看看exec.execute(mFuture)里面做了什么。
因为exec是一个SerialExecutor。所以这里直接贴出了它的代码。它是AsyncTask的一个静态内部类。

private static class SerialExecutor implements Executor {
final ArrayDeque mTasks = new ArrayDeque();
Runnable mActive;
//这里出入的是一个Runnable。上面的mFuture是FutureTask,FutureTask实现了Runnable接口。所以可以直接传进来。
public synchronized void execute(final Runnable r) {
mTasks是一个ArrayDeque它是一个双端队列(支持对头插入或者队尾插入) mTasks.offer()是在队尾插入。
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
//如果没有任务在执行。
if (mActive == null) {
scheduleNext();
}
}

    protected synchronized void scheduleNext() {
    //mTasks.poll()从对头中取出一个任务。如果有任务的话。
        if ((mActive = mTasks.poll()) != null) {
        //线程池就去执行mActive这个任务 ,THREAD_POOL_EXECUTOR是一个线程池。 看下面
            THREAD_POOL_EXECUTOR.execute(mActive);
        }
    }
}
//THREAD_POOL_EXECUTOR在这里。
public static final Executor THREAD_POOL_EXECUTOR;
static {
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>(), sThreadFactory);
    threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);
  //  主要是这句。 这个静态代码块是用于创建线程池的。
    THREAD_POOL_EXECUTOR = threadPoolExecutor;
}

看看创建线程池的参数:
CORE_POOL_SIZE 核心线程数:这个值是1.
MAXIMUM_POOL_SIZE 最大线程数 :这个值是20
KEEP_ALIVE_SECONDS在没有任务的情况下线程存活的时间是3
TimeUnit.SECONDS 存活的时间单位是秒。意思是存活3秒就会被回收掉。
new SynchronousQueue SynchronousQueue没有容量,是无缓冲等待队列,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素。

拥有公平(FIFO)和非公平(LIFO)策略,非公平侧罗会导致一些数据永远无法被消费的情况?

使用SynchronousQueue阻塞队列一般要求maximumPoolSizes为无界(Integer.MAX_VALUE),避免线程拒绝执行操作。
sThreadFactory这个是创建线程的工厂
threadPoolExecutor.setRejectedExecutionHandler(sRunOnSerialPolicy);这里是设置拒绝任务的策略。

sRunOnSerialPolicy是什么东西?
//这里就是拒绝策略。简单来说就是上面创建的线程池不够用了就会触发这个拒绝策略的执行。因为上面使用的是SynchronousQueue并且最大线程数只设置了为20.所以很容易触发这里的拒绝策略。
private static ThreadPoolExecutor sBackupExecutor;
private static LinkedBlockingQueue sBackupExecutorQueue;
private static final RejectedExecutionHandler sRunOnSerialPolicy =
new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
android.util.Log.w(LOG_TAG, “Exceeded ThreadPoolExecutor pool size”);
// As a last ditch fallback, run it on an executor with an unbounded queue.
// Create this executor lazily, hopefully almost never.
synchronized (this) {
if (sBackupExecutor == null) {
//这里使用的队列因为没有设置队列长度,默认是Integer.MAX_VALUE所以会有内存溢出的风险
sBackupExecutorQueue = new LinkedBlockingQueue();
//触发拒绝策略之后,这里实现了一个自定义拒绝策略。 然后又创建了一个线程池去处理。这里创建的线程池的拒绝策略使用了默认的。因为这里创建的时候并没有指定拒绝策略,所以系统会使用默认的。private static final RejectedExecutionHandler defaultHandler = new AbortPolicy();ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务

sBackupExecutor = new ThreadPoolExecutor( BACKUP_POOL_SIZE, BACKUP_POOL_SIZE, KEEP_ALIVE_SECONDS,TimeUnit.SECONDS,sBackupExecutorQueue, sThreadFactory);
//当任务空闲的时候,等待时间超过了设置的等待时间就关闭空闲的线程 sBackupExecutor.allowCoreThreadTimeOut(true);
}
}
//启用新的线程池去执行任务。
sBackupExecutor.execute®;
}
};

//线程池里面执行的任务就是这个
mFuture = new FutureTask(mWorker) {
@Override
protected 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);
}
}
};
看postResultIfNotInvoked(get)方法
private void postResultIfNotInvoked(Result result) {
final boolean wasTaskInvoked = mTaskInvoked.get();//这里取到正在任务是否被调用了。
if (!wasTaskInvoked) {
postResult(result);
}
}
//如果任务没有被消耗:
private Result postResult(Result result) {
@SuppressWarnings(“unchecked”)
Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult(this, result));
message.sendToTarget();//发送handler消息
return result;
}
看看getHandler
private Handler getHandler() {
return mHandler;
}
//再看看handler是怎么创建的。这里创建的是一个主线程的handler。
public AsyncTask(@Nullable Looper callbackLooper) {
mHandler = callbackLooper == null || callbackLooper == Looper.getMainLooper()
? getMainHandler()
: new Handler(callbackLooper);
全程只用到了主线程的handler。

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