(注意:本文基于API 28的源码分析,不同的API的源码不同)
类加载时机
第一次在主线程中创建AsyncTask子类对象时,AsyncTask类作为其父类,会优先加载到内存中,它持有的类变量、静态代码块会在AsyncTask类加载的初始化阶段,合并成一个<clinit>(类构造器),<clinit>方法会执行,接下来看看<clinit>中有哪些语句执行
注意:本文根据AsyncTask中静态成员的编写顺序叙述
LOG_TAG
private static final String LOG_TAG = "AsyncTask";
AsyncTask类持有的一个常量,用于过滤日志
CPU_COUNT
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
AsyncTask类持有的一个常量,用于当前Android设备的CPU核心数(磊哥显然看过AsyncTask源码,代码都一样……
2、核心线程池的线程总数,注意不管CPU核心有多少,CORE_POOL_SIZE的最大值为4
private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4));
3、线程池的线程总数则是CPU核心数乘以2,而后再+1
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
4、线程存活时间30s
private static final int KEEP_ALIVE_SECONDS = 30;
5、ThreadFactory对象,用于创建Thread对象
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());
}
};
ThreadFactory为一个interface、它内部只定义了一个newThread方法,该处通过匿名内部类创建,重写了newThread方法,在newThread方法内部通过new Thread(Runnable, String)创建Thread对象,好处是为AsyncTask创建的每一个Thread对象,都起了名字“AsyncTask #” + 原子类持有的int值,确保线程名字的唯一性(ThreadFactory对象持有的一个AtomicInteger对象mCount)
6、基于链表的有界阻塞队列,最大持有128个Runnable,后面看看它会给哪个线程池使用
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
7、AsyncTask类持有的第一个线程池
public static final Executor THREAD_POOL_EXECUTOR;
8、静态代码块,创建了一个线程池对象,由THREAD_POOL_EXECUTOR负责持有(见7号知识点)
static {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
sPoolWorkQueue, sThreadFactory);
threadPoolExecutor.allowCoreThreadTimeOut(true);
THREAD_POOL_EXECUTOR = threadPoolExecutor;
}
首先创建一个ThreadPoolExecutor对象,由局部变量threadPoolExecutor暂时持有,看下ThreadPoolExecutor构造方法的传入参数
a、CORE_POOL_SIZE(见2号知识点) 代表核心线程数量
b、MAXIMUM_POOL_SIZE(见3号知识点)代表线程池内的线程最大数量
c、KEEP_ALIVE_SECONDS(见4号知识点)代表核心线程与非核心线程的存活时间(后面解释为何代表核心线程的存活时间)
d、TimeUnit.SECONDS 代表线程存活时间的单位,此处单位是秒
e、sPoolWorkQueue(见6号知识点)代表阻塞队列,它负责持有任务
f、sThreadFactory(见5号知识点)代表线程工厂,它负责创建线程
然后通过threadPoolExecutor的allowCoreThreadTimeOut方法,传入true,代表核心线程也超时(默认值是false,这样KEEP_ALIVE_SECONDS就代表核心线程与非核心线程的存活时间)
最终会由AsyncTask的类变量THREAD_POOL_EXECUTOR负责持有
9、创建一个SerialExecutor对象,由AsyncTask类的SERIAL_EXECUTOR持有,详细代码(见13号知识点)
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
10、AsyncTask类持有的两个常量,后面看看要做什么
private static final int MESSAGE_POST_RESULT = 0x1;
private static final int MESSAGE_POST_PROGRESS = 0x2;
11、AsyncTask类持有的sDefaultExecutor,默认指向的是SERIAL_EXECUTOR(见9号知识点)
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
12、AsyncTask类持有的一个Handler对象sHandler,Handler机制太重要,无处不见
private static InternalHandler sHandler;
13、静态内部类
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);
}
}
}
a、SerialExecutor对象持有一个ArrayDeque对象mTasks,它是双端队列(即能做栈、又能做队列)、持有一个Runnable对象mActive
b、为重写的execute方法,增加了一个synchronized修饰,同一时刻,获得对象锁的线程才能执行该方法,目的是为了共享变量mTasks的插入元素,在同一个时刻只有一个元素插入,在execute方法内部做了两件事情,第一是调用了mTasks的offer方法,插入了一个Runnable对象,在该Runnable对象重写的run方法内部,首先调用传入的Runnable对象r的run方法,然后会一定会执行的scheduleNext()方法,第二是当mActivity为null,会执行scheduleNext()方法
c、scheduleNext方法,从ArrayDeque对象mTasks取出Runnable对象,交由mActive持有,然后会在成功获取到任务到情况下,将任务提交到一个线程池里(见7号知识点),由线程池中的线程负责执行任务
14、获取一个主线程的Handler对象,它的唯一调用处是AsyncTask对象初始化持有的mHandler位置处
private static Handler getMainHandler() {
synchronized (AsyncTask.class) {
if (sHandler == null) {
sHandler = new InternalHandler(Looper.getMainLooper());
}
return sHandler;
}
}
15、用于变更默认的Executor(hide修饰)
public static void setDefaultExecutor(Executor exec) {
sDefaultExecutor = exec;
}
总结
a、AsyncTask利用了Java现有的线程池技术
b、AsyncTask类持有一个线程池、由AsyncTask类的THREAD_POOL_EXECUTOR负责持有(一个常量)
c、AsyncTask对象提交的任务是串行执行(默认实现),意味着同一时刻只有一个Runnable会在线程池中执行
e、如果想要同一时刻多个Runnable并行,就需要你调用executeOnExecutor方法,并传入一个自定义的Executor实现类
f、Executor接口定义了作为执行者的规范,作者巧妙的实现了一个具备Executor能力的实现类SerialExecutor和线程池ThreadPoolExecutor配合的如此默契,厉害!(注意:实现Executor接口的类,不能算做线程池类,只能说是具备Executor的能力)