PicassoExecutorService 本质上是线程池,所以借此将 Java 线程池这块的关系也梳理一下。
几个概念简单说一下,
Runnable,Callable 两者区别应该是仅是否有返回值的区别。
Future 通过它可以获取到线程执行的状态及结果。

如果想要利用线程池执行任务,有这么几个步骤,
- 创建线程池
- 通过 submit 方法添加任务
- 等待结果,如不再需要线程池,可以用 shutdown 方法停止任务及关掉池子。
回到 PicassoExecutorService,构造方法创建了一个固定线程数为 3 个线程池,队列采用 PriorityBlockingQueue 类型,应该是要控制线程优先级,提供了 PicassoThreadFactory 工厂类。
假设这个时候有个图片加载的任务需要执行,那么会通过 submit 方法执行,
public Future<?> submit(Runnable task) {
PicassoFutureTask ftask = new PicassoFutureTask((BitmapHunter) task);
execute(ftask);
return ftask;
}
Runnable 类型的 task 被强转成了 BitmapHunter,看来这个 BitmapHunter 肯定实现了 Runnable。简单看来下,其内部方法还是挺多的,看来是个核心类,暂且不看,先知道一下。
PicassonFutureTask 对 BitmapHunter 进行了包装,并可以进行优先级的比较。
执行任务时,我们简单理解为就是给任务分配了一个线程,然后执行 BitmapHunter 对象 run 方法的逻辑。
在分析 BitmapHunter 前,再来看下 Picasso 的这个线程是怎么生产的,
static class PicassoThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
return new PicassoThread(r);
}
}
private static class PicassoThread extends Thread {
PicassoThread(Runnable r) {
super(r);
}
@Override public void run() {
Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
super.run();
}
}
线程的特殊点在于执行任务之前,配置了线程的优先级,THREAD_PRIORITY_BACKGROUND 的优先级略低于普通的线程,从而确保在不影响用户正常操作上,进行图片加载。
最后来看下如何调用到 BitmapHunter 的 run 方法,
public void execute(Runnable command) {
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
//从 execute 说起,入参的 command 就是 PicassoFutureTask 对象
//在满足条件的情况下,会被包装成一个 Worker 对象
if (addWorker(command, true))
return;
c = ctl.get();
}
//省略
}
private boolean addWorker(Runnable firstTask, boolean core) {
//省略了很多代码,只挑相关的
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//Worker 是 ThreadPoolExecutor 类的内部类,实现了 Runnable 接口
//里面有两个关键属性,firstTask 和 thread
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
workers.add(w);
workerAdded = true;
if (workerAdded) {
//如果 woker 对象添加成功,就会启动相关联的线程
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
//Worker 对象的创建是这样的
Worker(Runnable firstTask) {
//这个还是最开始的 Runnable 对象,即 PicassoFutureTask 对象
this.firstTask = firstTask;
//这个线程的创建是不是有些熟悉,通过工厂方法创建,
//而这个工厂对象类型就是 PicassoThreadFactory
//可见创建的就是 PicassoThread,注意 newThread 方法的入参
this.thread = getThreadFactory().newThread(this);
}
//所以前面说的启动 Worker 关联的线程,会执行的 run 方法其实最终执行了 Workder 的 run 方法
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Runnable task = w.firstTask;
try {
//只看最关键的,这里又调了 firstTask 的 run 方法
//而这个 firstTask 不就是 execute 方法的入参么
//但 PicassoFutureTask 是对 BitmapHunter 进行了包装,最终调用的就是
//BitmapHunter 对象的 run 方法
task.run();
} finally {
processWorkerExit(w, completedAbruptly);
}
}
至此,关于 PicassoExecutorService 的大概内容也算有个了解了,下一步的重点是了解如何产生 BitmapHunter 对象,以及 BitmapHunter 实际做了些什么。
网友评论