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;
}
- PicassoFutureTask继承类FutureTask,它返回的结果类型是BitmapHunter(Runnable子类)。PicassFutureTask接收BitmapHunter创建FutureTask,且该FutureTask返回结果为空。
- 因为PicassoExecutorService使用了优先级无限队列PriorityBlockingQueue作为任务队列,所以PicassoFutureTask实现了Comparable接口。通过比较BitmapHunter的priority和sequence属性确定优先级,优先级高的任务将优先被取出队列执行。先比较BitmapHunnter的priority属性,如果相同再比较BitmapHunter的创建顺序sequence。
- 当有任务BimtapHunter被提交到PicassoExecutorService中,该任务会被封装成PicassoFutureTask,或被立刻执行或被放进PriorityBlockingQueue等待执行,然后立即返回创建PicassoFutureTask。