Picasso 源码 commit 记(7):多线程来了

236 阅读2分钟

以下代码笔记基于 commitId:e7aac97343063c85956224b9de9165eb070b1984,commit 时间:2013/2/21, 4:28 AM。点击上面的 commitId 可以跳转到 github 看代码,配合本文阅读。

本系列的文章结构包括以下 6 个部分。重构 是同样功能的代码的变动。fix 是修复的 bug 。 feature 是对比上次提交,这次提交的新功能。设计 是我觉得可以提一下的代码设计,这部分可能不同的程序员会做不同的设计。疑惑 是我看代码过程中觉得有问题或者不懂的地方。知识点 是关于 Java 或者安卓的一些通用知识。

重构

picasso 也改成用 Builder 模式

这次提交把 picasso 改成了用 Builder 模式构造,这样就可以方便给 picasso 配置不同的内部组件,例如 ExecutorService 。

feature

多线程来了

之前 picasso 的线程池用的 singleThreadExecutor ,这次改成了 Executors.newFixedThreadPool(3, new PicassoThreadFactory()) 。这意味着最多会有三个线程同时处理请求,也意味着后面有些地方要处理并发问题啦(瑟瑟发抖)。

知识点

自定义线程工厂

可以看到上面生成线程池的时候传了一个 PicassoThreadFactory 对象,这是 Picasso 自定义的线程工厂类。

static class PicassoThreadFactory implements ThreadFactory {
    private static final AtomicInteger id = new AtomicInteger();

    @SuppressWarnings("NullableProblems") public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setName("picasso-" + id.getAndIncrement());
        t.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
        
        return t;
    }
}

这可以设置线程的名字,方便调试的时候只观察我们自己生成的线程。还可以设置线程的优先级。注意生成的线程名字包含线程的个数,线程数用了 AtomicInteger。刚说完“意味着我们要处理并发问题”,马上就遇到了。

为什么要用 AtomicInteger

线程工厂是在线程池生成线程的时候用到的,线程池生成线程有并发问题吗?这取决于使用情况。例如,PicassoThreadFactory 的 AtomicInteger id 变量是 static 的,意味着当有多个线程池使用 PicassoThreadFactory 的时候,它们是共用一个 id 的,这就可能会有多线程问题(这不是唯一的并发场景)。在实际中,线程工厂的实现最好是写成线程安全的, 因为你无法保证它会不会用在多线程场景。