Glide之线程池使用实战分析

Glide里面的几个线程池

Glide 源码解析 之 线程池

了解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请求数据的过程和缓存到磁盘的过程

扫描二维码关注公众号,回复: 11039378 查看本文章

请求网络数据是在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使用对象池创建的过程

发布了189 篇原创文章 · 获赞 25 · 访问量 22万+

猜你喜欢

转载自blog.csdn.net/lizhongyisailang/article/details/104212365