了解Glide的线程池,先看上面两篇文章,之后我们说一下,在实际的一次请求过程中,线程池是怎么用的?只看最一般默认的流程:
一次网络请求,从Engine的load方法开始,其中会获取到EngineJob和DecodeJob实例,engineJob.start(decodeJob)就开始了流程
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
看一个decodeJob的willDecodeFromCache方法:
boolean willDecodeFromCache() {
Stage firstStage = getNextStage(Stage.INITIALIZE);
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
这块就不展开了,默认是返回true的,返回到EngineJob的start方法,executor是diskCacheExecutor,diskCacheExecutor是一个单线程的线程池,decodeJob实现了Runnable接口,executor.execute(decodeJob)就是在diskCacheExecutor的线程中执行decodeJob。
这里不具体展开DecodeJob的执行过程,大概了执行ResourceCacheGenerator的startNext方法从RESOURCE_CACHE(在磁盘中)中取数据,没有取到执行DataCacheGenerator的startNext方法从DATA_CACHE(在磁盘中,存的原始数据)中取数据,这些操作都是在diskCacheExecutor的线程池中进行的,如果在DATA_CACHE中也没取到,就要执行SourceGenerator的startNext方法从网络(具体是由ModelLoader来决定的)去加载数据,注意重点来了,执行SourceGenerator的startNext方法,需要切换线程,看下面代码:
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
我们看stage等于Stage.SOURCE时,说明currentGenerator就是SourceGenerator了,看reschedule
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
runReason变成了SWICH_TO_SOURCE_SERVICE,callback是EngineJob(实现了DecodeJob.Callback接口),我们看EngineJob的reschedule方法:
@Override
public void reschedule(DecodeJob<?> job) {
// Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
// up.
getActiveSourceExecutor().execute(job);
}
private GlideExecutor getActiveSourceExecutor() {
return useUnlimitedSourceGeneratorPool
? sourceUnlimitedExecutor : (useAnimationPool ? animationExecutor : sourceExecutor);
}
默认是sourceExecutor,sourceExecutor最多有4个线程,根据手机的CPU个数来决定。看到没?DecodeJob这个Runnable又“跑到”sourceExecutor线程池里执行了,需要说明一下上面说的DecodeJob的run方法会在diskCacheExecutor线程中执行完的,不影响。大家想想是为什么?这是应该不同线程都有自己的执行栈,每个方法的调用状态都在对应线程的栈里面。
在SourceExecutor线程池里执行SourceGenerator的startNext方法,看这篇文章Glide之SourceGenerator请求数据的过程和缓存到磁盘的过程
请求网络数据是在SourceExecutor的线程0里面,数据请求回来:
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should
// reschedule to get back onto Glide's thread.
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
根据DiskCacheStrategy,默认是AUTOMATIC,网络请求数据isDataCacheable是true
public boolean isDataCacheable(DataSource dataSource) {
return dataSource == DataSource.REMOTE;
}
看cb.reschedule,这个cb是DecodeJob(实现了DataFetcherGenerator.FetcherReadyCallback接口),看看DecodeJob的reschedule方法:
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
这个方法我们分析过,就是回到EngineJob中,用SourceExecutor线程池第二次执行DecodeJob(这是第三次执行DecodeJob),根据上面的分析,我们知道还会执行到SourceGenerator的startNext方法,这次只是走了保存到本地缓存的逻辑。
总结一下:
第一次执行DecodeJob,是尝试从磁盘缓存RESOURCE_CACHE或者DATA_CACHE中获取数据,这些工作是在DiskCacheExecutor的线程池中做的,这是一个单线程池,如果没有获得数据。reschedule,通过到EngineJob中切换到SourceExecutor线程池
第二次执行DecodeJob,在SourceExecutor线程池中,执行SourceGenerator的startNext去网络获取数据。
第三次执行DecodeJob,获取到网络数据后,需要再reschedule一遍,让SourceExecutor线程池去保存数据到磁盘,可以不是同一个线程,具体看SourceExecutor的实现,我这个手机SourceExecutor中有4个线程,第二次和第三次是在同一个线程池中的不同线程中。
这三次执行,执行的是同一个DecodeJob对象。
进一步学习内容
(1)ThreadPoolExecutor内部实现、ExecutorService的具体用处
(2)EngineJob和DecodeJob使用对象池创建的过程