Android小知识-剖析OkHttp中的任务调度器Dispatcher

OkHttp发送的同步或异步请求队列的状态会在dispatcher中进行管理,dispatcher的作用就是用于维护同步和异步请求的状态,内部维护一个线程池,用于执行相应的请求。

在dispatcher内部维护着三个队列,这三个队列如下:

    private final Deque<RealCall.AsyncCall> readyAsyncCalls = new ArrayDeque<>();

    private final Deque<RealCall.AsyncCall> runningAsyncCalls = new ArrayDeque<>();

    private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();

runningAsyncCalls表示的是正在执行的异步请求队列。

readyAsyncCalls表示就绪状态的异步请求队列,如果当前的请求不满足某种条件时,当前的异步请求会进入就绪等待的异步请求队列中,当满足某种条件时,会从就绪等待的异步请求队列中取出异步请求,放入正在执行的异步请求队列中。

runningSyncCalls表示的正在执行的同步请求队列。

除了上面的三个队列,还有一个参数也是非常重要的,如下:

private @Nullable ExecutorService executorService;

executorService就是一个线程池对象,OkHttp的异步请求操作会放入这个线程池中。

OkHttp的异步请求在dispatcher中的一系列操作可以理解为生产者消费者模式,其中Dispatcher是生产者,它是运行在主线程中的,ExecutorService代表消费者池。

当同步和异步请求结束后,会调用dispatcher的finished方法,将当前的请求从队列中移除。

   client.dispatcher().finished(this);

这段代码是在finally块中,也就是说,无论请求成不成功,还是出现异常,这段代码都会执行,保证了请求的整个生命周期从开始到销毁。 

接下来,我们重新看看同步请求和异步请求在dispatcher中的操作。

1、同步请求会执行dispatcher的executed方法:

  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

在executed方法中,只是将当前请求RealCall存入正在执行的同步请求队列中。

2、异步请求会执行dispatcher的enqueue方法;

    private int maxRequests = 64;
    private int maxRequestsPerHost = 5;
    synchronized void enqueue(RealCall.AsyncCall call) {
        if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
            //第一步
            runningAsyncCalls.add(call);
            executorService().execute(call);
        } else {
            //第二步
            readyAsyncCalls.add(call);
        }
    }

上一节在讲解异步请求时已经解释过了,这里直接复制过来:在enqueue方法前使用了synchronized关键字进行修饰,也就是为这个方法加了个同步锁,继续往下看第一步,先是判断当前异步请求总数是否小于设定的最大请求数(默认是64),以及正在运行的每个主机请求数是否小于设定的主机最大请求数(默认是5),如果满足这两个条件,就会把传递进来的AsyncCall对象添加到正在运行的异步请求队列中,然后通过线程池执行这个请求。如果满足不了上面的两个条件就会走第二步,将AsyncCall对象存入readyAsyncCalls队列中,这个readyAsyncCalls就是用来存放等待请求的一个异步队列。

其中线程池的创建和获取代码如下:

  public synchronized ExecutorService executorService() {
    if (executorService == null) {
      executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
          new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
    }
    return executorService;
  }

创建线程池时,第一个参数表示核心线程数,设置为0,当线程池空闲一段时间后,就会将线程池中的所有线程进行销毁;第二个参数表示最大线程数,设置为整型的最大值,具体多少线程数还是受限OkHttp中的maxRequests这个参数;第三个参数表示当我们的线程数大于核心线程数的时候,多余的空闲线程存活的最大时间为60秒,结合第一个核心线程数为0,也就是说OkHttp中的线程在工作完毕后,会在60秒后进行关闭。

技术共享笔记

©️2020 CSDN 皮肤主题: 猿与汪的秘密 设计师:上身试试 返回首页