美文网首页Android开发经验谈Android文章Android开发
Android小知识-剖析OkHttp中的任务调度器Dispat

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

作者: 爱读书的顾先生 | 来源:发表于2018-10-24 08:22 被阅读1107次

    本平台的文章更新会有延迟,大家可以关注微信公众号-顾林海,包括年底前会更新kotlin由浅入深系列教程,目前计划在微信公众号进行首发,如果大家想获取最新教程,请关注微信公众号,谢谢

    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秒后进行关闭。


    838794-506ddad529df4cd4.webp.jpg

    搜索微信“顾林海”公众号,定期推送优质文章。

    相关文章

      网友评论

        本文标题:Android小知识-剖析OkHttp中的任务调度器Dispat

        本文链接:https://www.haomeiwen.com/subject/pqfttqtx.html