多线程之 AsyncTask 使用详解和从源码中深入理解 AsyncTask 机制(1)

/**

WorkerRunnable类的构造函数

*/

private static abstract class WorkerRunnable<Params, Result> implements Callable {

// 此处的Callable也是任务;

// 与Runnable的区别:Callable存在返回值 = 其泛型

Params[] mParams;

}

/**

  • 分析:FutureTask类的构造函数

  • 定义:1个包装任务的包装类

  • 注:内部包含Callable 、增加了一些状态标识 & 操作Callable的接口

*/

public FutureTask(Callable callable) {

if (callable == null)

throw new NullPointerException();

this.callable = callable;

this.state = NEW;

}

// 回到调用原处

/**

  • postResultIfNotInvoked()

*/

private void postResultIfNotInvoked()(Result result) {

// 取得任务标记

final boolean wasTaskInvoked = mTaskInvoked.get();

// 若任务无被执行,将未被调用的任务的结果通过InternalHandler传递到UI线程

if (!wasTaskInvoked) {

postResult(result);

}

}

  • 创建了1个WorkerRunnable类 的实例对象 & 复写了call()方法;

  • 创建了1个FutureTask类 的实例对象 & 复写了 done();

2、execute(Params… params)


/**

  • 具体使用

*/

mTask.execute();

/**

  • 源码分析:AsyncTask的execute()

*/

public final AsyncTask<Params, Progress, Result> execute(Params… params) {

return executeOnExecutor(sDefaultExecutor, params);

// ->>分析1

}

/**

  • executeOnExecutor(sDefaultExecutor, params)

  • 参数说明:sDefaultExecutor = 任务队列 线程池类(SerialExecutor)的对象

*/

public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,Params… params) {

// 判断 AsyncTask 当前的执行状态

// PENDING = 初始化状态

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

}

}

// 将AsyncTask状态设置为RUNNING状态

mStatus = Status.RUNNING;

// 主线程初始化工作

onPreExecute();

// 添加参数到任务中

mWorker.mParams = params;

// 执行任务

// 此处的exec = sDefaultExecutor = 任务队列 线程池类(SerialExecutor)的对象

exec.execute(mFuture);

return this;

}

/**

  • exec.execute(mFuture)

  • 说明:属于任务队列 线程池类(SerialExecutor)的方法

*/

private static class SerialExecutor implements Executor {

// SerialExecutor = 静态内部类

// 即 是所有实例化的AsyncTask对象公有的

// SerialExecutor 内部维持了1个双向队列;

// 容量根据元素数量调节

final ArrayDeque mTasks = new ArrayDeque();

Runnable mActive;

// execute()被同步锁synchronized修饰

// 即说明:通过锁使得该队列保证AsyncTask中的任务是串行执行的

// 即 多个任务需1个个加到该队列中;然后 执行完队列头部的再执行下一个,以此类推

public synchronized void execute(final Runnable r) {

// 将实例化后的FutureTask类 的实例对象传入

// 即相当于:向队列中加入一个新的任务

mTasks.offer(new Runnable() {

public void run() {

try {

r.run();

} finally {

scheduleNext();

}

}

});

// 若当前无任务执行,则去队列中取出1个执行

if (mActive == null) {

scheduleNext();

}

}

//

protected synchronized void scheduleNext() {

// 取出队列头部任务

if ((mActive = mTasks.poll()) != null) {

// 执行取出的队列头部任务

// 即调用执行任务线程池类(THREAD_POOL_EXECUTOR)

THREAD_POOL_EXECUTOR.execute(mActive);

}

}

}

  • 执行任务前,通过 任务队列 线程池类(SerialExecutor)将任务按顺序放入到队列中;

  • 通过同步锁修饰execute()从而保证AsyncTask中的任务是串行执行的;

  • 之后的线程任务执行是 通过任务线程池类(THREAD_POOL_EXECUTOR) 进行的;

3、THREAD_POOL_EXECUTOR.execute()


/**

  • 源码分析:THREAD_POOL_EXECUTOR.execute()

  • 说明:

  • a. THREAD_POOL_EXECUTOR实际上是1个已配置好的可执行并行任务的线程池
    
  • b. 调用THREAD_POOL_EXECUTOR.execute()实际上是调用线程池的execute()去执行具体耗时任务
    
  • c. 而该耗时任务则是步骤2中初始化WorkerRunnable实例对象时复写的call()
    
  • 注:下面先看任务执行线程池的线程配置过程,看完后请回到步骤2中的源码分析call()

*/

// 参数设置

//获得当前CPU的核心数

private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();

//设置线程池的核心线程数2-4之间,但是取决于CPU核数

private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));

//设置线程池的最大线程数为 CPU核数*2+1

private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;

//设置线程池空闲线程存活时间30s

private static final int KEEP_ALIVE_SECONDS = 30;

//初始化线程工厂

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

}

};

//初始化存储任务的队列为LinkedBlockingQueue 最大容量为128

private static final BlockingQueue sPoolWorkQueue =

new LinkedBlockingQueue(128);

// 根据参数配置执行任务线程池,即 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,

sPoolWorkQueue, sThreadFactory);

// 设置核心线程池的 超时时间也为30s

threadPoolExecutor.allowCoreThreadTimeOut(true);

THREAD_POOL_EXECUTOR = threadPoolExecutor;

}

4、call()

/**

  • AsyncTask的构造函数

*/

public AsyncTask() {

// 初始化WorkerRunnable变量 = 一个可存储参数的Callable对象

mWorker = new WorkerRunnable<Params, Result>() {

public Result call() throws Exception {

// 添加线程的调用标识

mTaskInvoked.set(true);

Result result = null;

try {

// 设置线程的优先级

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

// 执行异步操作 = 耗时操作

// 即 我们使用过程中复写的耗时任务

result = doInBackground(mParams);

Binder.flushPendingCommands();

} catch (Throwable tr) {

mCancelled.set(true);// 若运行异常,设置取消的标志

throw tr;

} finally {

// 把异步操作执行的结果发送到主线程

// 从而更新UI ->>分析1

postResult(result);

}

return result;

}

};

}

/**

  • postResult(result)

*/

private Result postResult(Result result) {

@SuppressWarnings(“unchecked”)

// 创建Handler对象 ->> 源自InternalHandler类

Message message = getHandler().obtainMessage(MESSAGE_POST_RESULT,

new AsyncTaskResult(this, result));

// 发送消息到Handler中

message.sendToTarget();

return result;

}

/**

  • InternalHandler类

*/

private static class InternalHandler extends Handler {

// 构造函数

public InternalHandler() {

super(Looper.getMainLooper());

// 获取的是主线程的Looper()

// 故 AsyncTask的实例创建 & execute()必须在主线程使用

}

@Override

public void handleMessage(Message msg) {

AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;

switch (msg.what) {

// 若收到的消息 = MESSAGE_POST_RESULT

// 则通过finish() 将结果通过Handler传递到主线程

case MESSAGE_POST_RESULT:

result.mTask.finish(result.mData[0]); ->>分析3

break;

// 若收到的消息 = MESSAGE_POST_PROGRESS

// 则回调onProgressUpdate()通知主线程更新进度的操作

case MESSAGE_POST_PROGRESS:

result.mTask.onProgressUpdate(result.mData);

break;

最后

我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习

已经将知识体系整理好(源码,笔记,PPT,学习视频)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

andler {

// 构造函数

public InternalHandler() {

super(Looper.getMainLooper());

// 获取的是主线程的Looper()

// 故 AsyncTask的实例创建 & execute()必须在主线程使用

}

@Override

public void handleMessage(Message msg) {

AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;

switch (msg.what) {

// 若收到的消息 = MESSAGE_POST_RESULT

// 则通过finish() 将结果通过Handler传递到主线程

case MESSAGE_POST_RESULT:

result.mTask.finish(result.mData[0]); ->>分析3

break;

// 若收到的消息 = MESSAGE_POST_PROGRESS

// 则回调onProgressUpdate()通知主线程更新进度的操作

case MESSAGE_POST_PROGRESS:

result.mTask.onProgressUpdate(result.mData);

break;

最后

我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习

已经将知识体系整理好(源码,笔记,PPT,学习视频)

[外链图片转存中…(img-bnXCRf7B-1714670703047)]

[外链图片转存中…(img-SluyEdtm-1714670703047)]

[外链图片转存中…(img-fARvAdG0-1714670703048)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值