Picasso源码阅读笔记四

305 阅读4分钟

Picasso使用线程池来并发处理图片请求。

我们可以使用Picasso提供的线程池PicassoExecutorService,也可使用自定义的,如

new Picasso.Builder(context).executor(customExecutorService).build()

多线程预备知识

1.这里先解释下ThreadPoolExecutor的构造函数参数。

ThreadPoolExecutor(
	int corePoolSize,
	int maximumPoolSize,
	long keepAliveTime,
	TimeUnit unit,
	BlockingQueue<Runnable> workQueue,
	ThreadFactory threadFactory
)
  • corePoolSize:核心线程数。当提交一个任务到线程池时,如果当前线程数小于corePoolSize,线程池会创建一个线程执行任务,即使当前已有线程处于空闲状态。如果调用了线程池的prestartAllCoreThreads方法,线程池会提前创建并启动所有核心线程。
  • maximumPoolSize:线程池允许创建的最大线程数。当阻塞队列满了且当前线程数少于最大线程数,线程池会创建新线程来执行任务。如果阻塞队列是无界的,线程池不会创建除了核心线程外的线程。
  • keepAliveTime和TimeUnit:这个是非核心的线程空闲后等待新任务的最长时间,超过这个时间线程就会被终止。
  • BlockingQueue:用来保存等待执行的任务的阻塞队列。
  • ThreadFactory:用于创建线程的工厂。

2.Runnable、Callable、Future、FutureTask、ThreadPoolExecutor

  • Runnable与Callable的区别是,Runnable代表没有返回结果的任务,Callable代表有返回结果的任务。可以用Executor.callable(Runnable task, T result)方法把Runnable转化为Callable。
  • Future是一个接口,代表异步计算的结果。
  • 类FutureTask实现了Future、Runnable接口。
  • FutureTask的泛型参数代表FutureTask返回结果的类型。
  • FutureTask有三种状态。未启动,刚创建,run方法为被调用。已启动,run方法被调用未执行完成。已完成,run方法执行完成。
  • 当FutureTask未启动或已启动,FutureTask.get()导致调用线程阻塞。当FutureTask已完成时,FutureTask.get()方法导致调用线程立即返回或者抛出异常。
  • 当FutureTask未启动,FutureTask.cancel()会导致任务不会执行。当FutureTask已启动,FutureTask.cancel(true)会已中断任务线程的方式终止任务,FutureTask.cancel(false)不会对任务执行有影响。当FutureTask已完成时,FutureTask.cancel()返回false。
  • 可以创建FutureTask,然后它当做Runnable交给Executor的execute方法执行。也可以把Runnable交给ThreadPoolExecutor.submit执行,返回得到FutureTask。这两种方式只是FutureTask的创建方式不同,其实都是把FutureTask当做Runnable交给Executor的execute方法执行。
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

####PicassoExecutorService源码解析 ######1.PicassoExecutorService的构造函数如下:

private static final int DEFAULT_THREAD_COUNT = 3;

PicassoExecutorService() {
	super(
		DEFAULT_THREAD_COUNT, 
		DEFAULT_THREAD_COUNT, 
		0, TimeUnit.MILLISECONDS,
		new PriorityBlockingQueue<Runnable>(), 
		new Utils.PicassoThreadFactory()
	);
}

该线程池使用了PriorityBlockingQueue,这是一个有优先级的无限阻塞队列。这说明除了核心线程,线程池不会创建其他线程。所以,keepAliveTime设为0,该线程池的核心线程数和最大线程数一样,默认都是3。

2.核心线程数随网络变化

void adjustThreadCount(NetworkInfo info) {
    if (info == null || !info.isConnectedOrConnecting()) {
      setThreadCount(DEFAULT_THREAD_COUNT);
      return;
    }
    switch (info.getType()) {
      case ConnectivityManager.TYPE_WIFI:
      case ConnectivityManager.TYPE_WIMAX:
      case ConnectivityManager.TYPE_ETHERNET:
        setThreadCount(4);
        break;
      case ConnectivityManager.TYPE_MOBILE:
        switch (info.getSubtype()) {
          case TelephonyManager.NETWORK_TYPE_LTE:  // 4G
          case TelephonyManager.NETWORK_TYPE_HSPAP:
          case TelephonyManager.NETWORK_TYPE_EHRPD:
            setThreadCount(3);
            break;
          case TelephonyManager.NETWORK_TYPE_UMTS: // 3G
          case TelephonyManager.NETWORK_TYPE_CDMA:
          case TelephonyManager.NETWORK_TYPE_EVDO_0:
          case TelephonyManager.NETWORK_TYPE_EVDO_A:
          case TelephonyManager.NETWORK_TYPE_EVDO_B:
            setThreadCount(2);
            break;
          case TelephonyManager.NETWORK_TYPE_GPRS: // 2G
          case TelephonyManager.NETWORK_TYPE_EDGE:
            setThreadCount(1);
            break;
          default:
            setThreadCount(DEFAULT_THREAD_COUNT);
        }
        break;
      default:
        setThreadCount(DEFAULT_THREAD_COUNT);
    }
}
private void setThreadCount(int threadCount) {
    setCorePoolSize(threadCount);
    setMaximumPoolSize(threadCount);
}

Picasso注册了BroadcastReceiver监听网络状态变化,调整核心线程数。Wifi网络下核心线程数调整为4,4G网络下核心线程数为3,3G网络下核心程数为2,2G网络下核心线程数为1,其他情况下核心线程数为默认值3。

3.PicassoThreadFactory线程工厂

static class PicassoThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable r) {
      return new PicassoThread(r);
    }
}

private static class PicassoThread extends Thread {
    public PicassoThread(Runnable r) {
      super(r);
    }

    @Override public void run() {
      Process.setThreadPriority(THREAD_PRIORITY_BACKGROUND);
      super.run();
    }
}

PicassoThreadFactory是创建线程PicassoThread的工厂。PicassoThread的线程优先级为THREAD_PRIORITY_BACKGROUND。

4.PicassoFutureTask

private static final class PicassoFutureTask extends FutureTask<BitmapHunter>
      implements Comparable<PicassoFutureTask> {//见下面第1点
    private final BitmapHunter hunter;

    public PicassoFutureTask(BitmapHunter hunter) {//见下面第1点
      super(hunter, null);
      this.hunter = hunter;
    }

    @Override
    public int compareTo(PicassoFutureTask other) {//见下面第2点
      Picasso.Priority p1 = hunter.getPriority();
      Picasso.Priority p2 = other.hunter.getPriority();

      return (p1 == p2 ? hunter.sequence - other.hunter.sequence : p2.ordinal() - p1.ordinal());
    }
}

@Override
public Future<?> submit(Runnable task) {//见下面第3点
    PicassoFutureTask ftask = new PicassoFutureTask((BitmapHunter) task);
    execute(ftask);
    return ftask;
}
  1. PicassoFutureTask继承类FutureTask,它返回的结果类型是BitmapHunter(Runnable子类)。PicassFutureTask接收BitmapHunter创建FutureTask,且该FutureTask返回结果为空。
  2. 因为PicassoExecutorService使用了优先级无限队列PriorityBlockingQueue作为任务队列,所以PicassoFutureTask实现了Comparable接口。通过比较BitmapHunter的priority和sequence属性确定优先级,优先级高的任务将优先被取出队列执行。先比较BitmapHunnter的priority属性,如果相同再比较BitmapHunter的创建顺序sequence。
  3. 当有任务BimtapHunter被提交到PicassoExecutorService中,该任务会被封装成PicassoFutureTask,或被立刻执行或被放进PriorityBlockingQueue等待执行,然后立即返回创建PicassoFutureTask。