okhttp 原理笔记四:Dispatcher
一、关键组成:
1、private int maxRequests = 64 //总的最大请求数
2、private int maxRequestsPerHost = 5; //单个服务器的最大请求数
3、private @Nullable ExecutorService executorService; //线程池
4、private final Deque<AsyncCall> readyAsyncCalls // 异步等候队列
5、 private final Deque<AsyncCall> runningAsyncCalls //运行中的异步队列
6、 private final Deque<RealCall> runningSyncCalls //运行中的同步队列
二、有什么作用?
1、maxRequests 用于在运行网络请求前的判断,如果当前的运行中的异步队列 runningAsyncCalls 的总数大于或者等于maxRequests (也就是64个)时,则不再继续执行下去
2、maxRequestsPerHost 依葫芦画瓢,也是用于在运行网络请求前的判断,不过是在maxRequests判断通过之后,用来判断当前的网络请求数,是否超过单台目标服务器的请求数。例如,当前已经有5个请求发送给百度了,那么,如果接下来还有1个进来也是要找百度的,也就是第6个去找百度的请求,那么,就拒绝继续执行。(抱歉,发向百度的班车已满...)
4、readyAsyncCalls 用来存储当前的排队情况的,就是那些因为运行请求的队列满了,所以,丢在这里排队等
5、runningAsyncCalls 里面就是记录当前运行中的所有异步请求
6、runningSyncCalls 里面就是记录当前运行中的所有同步请求
三、为什么要这么组成?
1、里面的所有队列的具体实现都是 ArrayDeque ,这种队列的特点在于,这个类在作为栈使用时可能比Stack快,作为队列使用时比LinkedList快,看上去挺牛逼的存在。同时注意的是,它并不是线程安全的,可能是为了性能吧,所以用这个来存储请求
2、线程池的配置,关键在于它的核心线程数以及排队的队列,核心线程数是0,意味着任务进去直接跑到等候队列里去了,但是由于等候队列的容量为0,也就是进不去,那么,就只能直接新建额外的非核心线程了,当然,也是有数量限制的,就是 maxRequests ,另外就是这些线程一旦完成任务空闲了, 只会空闲个60秒就销毁了,所以,是这么一回事。
四、关键运行逻辑
1、readyAsyncCalls 的请求什么时候跑去runningAsyncCalls ?然后发生了什么? 这个主要是看 promoteAndExecute 方法:
第一步:遍历 readyAsyncCalls 集合
第二步:先后判断是否超出请求的所有总数,以及单个服务器的总数,如果随便一个超出了,就不再执行
第三步:如果没超过请求的限制,就将这个请求,从等候队列中,拿出来,放入运行中的队列,同时要对两个队列里面的元素的增删做相应的处理
第四步:迁移完元素后,既然进去运行中的队列了,就是要执行的,所以,接下来,就是通过线程池执行新进来的这些请求了