第一次写博客,说是博客,其实就是自己的学习笔记,希望能坚持下去!
OKHttp的简单请求示例:
OkHttpClient.Builder builder =new OkHttpClient.Builder();
OkHttpClient client = builder.build();
Request request =new Request.Builder()
.url("")
.build();
try {
// 同步请求
client.newCall(request).execute();
// 异步请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response)throws IOException {
}
});
} catch (IOException e) {
e.printStackTrace();
}
以下是自己做的请求顺序导图:
请求顺序结合图总结一下异步请求过程
- 如果满足异步执行条件,则入队并立即执行,否则,加入ready队列,等待合适的条件去将其取出;当一个请求执行结束,会调用Dispatcher的promoteCalls方法,会将ready队列中的AsyncCall取出,入队并开始执行,然后在线程池中调用所执行的Call的getResponseWithInterceptorChain(),获取到请求结果,并回调出去。
- 同步异步的执行区别:都是调用的getResponseWithInterceptorChain()方法,异步线程是通过线程池来执行的,而同步则是直接执行
Dispatcher类
1. 线程池
该类中,获取线程池的方法为executorService()
,该方法内部实现的是懒加载的无边界限制的线程池。
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
可见,OKHttp中使用的线程池是ThreadPoolExecutor
参数说明:
- 0:核心线程数量,0表示后台线程空闲后不会保留,经过一段时间后停止
- Integer.MAX_VALUE:线程池可容纳的最大线程数量
- TimeUnit.SECOND:线程池中的线程数量大于核心线程数量时,空闲线程等待60s即被终止,若小于,则立即终止
- new SynchronousQueue<Runnable>():线程等待队列
- 最后一个参数:线程工厂
这里,需要对SynchronousQueue进行说明:
该队列的特点是:每插入一个元素必须等待另一个元素的移除,每移除一个元素都会等待另一个元素的插入,也就是说,该队列内部其实没有元素,容量为0;这样设计的意义就是可以快速的传递元素,很适合高频率的请求处理。
2. 结束请求finished方法
- 先移除该call对象
- 根据传入的promoteCalls参数,确定是否调用promoteCalls()方法;若为同步请求,则该参数为false,若为异步请求,则参数为true,需要执行下一步的入队操作
3. promoteCalls()方法
该方法是操作队列,控制请求执行的关键,负责将ready队列的call转化为running状态
- 首先,它会判断当前执行的request是否大于64
- 若小于,则遍历ready队列,取出call并将其添加进running队列,调用线程池的execute(call)方法
- 遍历的终止条件:ready队列为空,或者running满足最大数量限制
回调该方法有三个时机: - 一个请求执行结束,finished方法中
- Dispatcher的setMaxRequestsPerHost()被调用
- Dispatcher的setMaxRequests()被调用
总结
该类控制着异步请求时的任务调度和线程池,并未直接负责请求的执行,配合线程池,实现了高并发,低阻塞的运行。
参考:这位大佬的博客
网友评论