美文网首页安卓
Picasso 图片加载库源码分析4-线程池

Picasso 图片加载库源码分析4-线程池

作者: jkwen | 来源:发表于2021-07-03 19:57 被阅读0次

PicassoExecutorService 本质上是线程池,所以借此将 Java 线程池这块的关系也梳理一下。

几个概念简单说一下,

Runnable,Callable 两者区别应该是仅是否有返回值的区别。
Future 通过它可以获取到线程执行的状态及结果。

PicassoExecutorService.jpg

如果想要利用线程池执行任务,有这么几个步骤,

  1. 创建线程池
  2. 通过 submit 方法添加任务
  3. 等待结果,如不再需要线程池,可以用 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 实际做了些什么。

相关文章

网友评论

    本文标题:Picasso 图片加载库源码分析4-线程池

    本文链接:https://www.haomeiwen.com/subject/gizuultx.html