OkHttp同步使用方法
OkHttp异步使用方法
- onResponse和onFailure都是在工作线程(子线程)中执行的。
同步和异步的区别
- 发起请求的方法调用(步骤3)
-- 同步调用call.execute;异步调用call.enqueue,并传入Callback对象。 - 阻塞线程与否
-- 同步会阻塞当前线程;异步不会阻塞当前线程,相反,会开启一个新的线程完成网络请求的操作。
异步/同步请求的流程
- AsynCall可以理解为Runnable。
- Dispatcher是分发器类,由该分发器类决定异步请求是执行还是就绪。
- Call是接口,真正的操作在其实现类RealCall中。
- 同步请求实际上就是通过
executed方法把请求(RealCall对象)添加到同步请求队列(runningSyncCalls)当中。
-- 进入call.execute方法-
getResponseWithInterceptorChain方法:拦截器链,内部依次调用拦截器,详细见后。-- 进入Dispatcher的
executed方法-- 同步请求队列
runningSyncCalls在Dispatcher类中定义。
Dispatcher类中定义了3种队列(异步就绪/缓存等待请求队列readyAsyncCalls, 异步执行队列runningAsyncCalls, 同步请求队列runningSyncCalls)。--进入
finished方法 --在进入调用的finished方法
- 首先执行
call.remove(call),从当前队列中移除同步请求(promoteCalls=false),如果不能移除则抛出异常。 - 再执行
runningCallsCount()计算目前还在运行的请求。
-- 进入runningCallsCount方法
runningCallsCount方法返回了正在执行的异步请求和正在执行的同步请求数量之和。
- 当
runningCallsCount == 0时表示Dispatch分发器类中没有可运行的请求。
-
同步请求步骤总结
异步请求
异步请求的关键方法enqueue
-- 异步请求调用的是Call的实现类RealCall中的enqueue
-
AsyncCall是Runnable的实现类。
--
dispatcher().enqueue方法 满足条件: 1. 异步执行runningAsyncCalls个数<最大请求数maxRequests; 2. 正在运行的每个主机的请求runningCallsForHost(call)<设置的主机请求数的最大值maxRequestsPerHost。
若满足条件,将AsyncCall添加到异步执行队列runningAsyncCalls中,再通过线程池执行该异步请求executorService().execute(call);
若不满足条件,则将AsyncCall添加到等待队列readyAsyncCalls中。-
调用
executorService().execute(call)时,由于executorService()返回的是一个线程池(见下),所以实际上是调用每个子线程(AsyncCall)的run方法。
-- 进入executorService()
- 使用synchronized关键字保证executorService线程池是单例。
- 该方法返回的就是一个线程池对象executorService。
- ThreadPoolExecutor的参数:
参数1: 核心线程池数量,设为0表示空闲一段时间后,会把所有的线程全部销毁。
参数2: 最大线程数,设为整型的最大值后理论上可以无限扩充线程最大值,但实际上受限于maxRequests(见上)。
参数3: 当线程数大于核心线程数,多余的空闲线程最大的存活时间,这里设为60s。
-- 进入AsyncCall的父类NamedRunnable
-- NamedRunnable的run()- AsyncCall的
execute()实现了这里的execute()。
-- 进入AsyncCall的execute()(关联1) - 所以为什么上面说
onFailure和onResponse是在子线程中执行的(这里的execute()在NamedRunnable的run()中)。
-
enqueue方法总结
- 1中判断当前call是指判断当前call是否只执行了一次(
if(executed))。
Dispatcher类
主要作用是维护请求队列。
总结 -异步请求流程
若满足条件 1. 异步执行
runningAsyncCalls个数<最大请求数maxRequests; 2. 正在运行的每个主机的请求runningCallsForHost(call)<设置的主机请求数的最大值maxRequestsPerHost时,通过Dispatcher直接把异步请求放到正在执行的线程池队列(runningAsyncCalls.add(call))中,通过线程池ThreadPool开启任务(executorService().execute(call))。若不满足条件,Dispatcher把异步请求放到就绪等待队列(
readyAsyncCalls)中,当异步执行队列runningAsyncCalls有空闲位置时,则从readyAsyncCalls中取出优先级高的请求放到runningAsyncCalls请求队列中执行。
- Q:readyAsyncCalls队列中的线程在什么时候才会被执行?
见AsyncCall的
execute()(关联1),最后的finally中总会执行的dispatcher().finished(this)。
-- 进入dispatcher().finished(this) -- 进入3个参数的finished- 步骤1: 调用
calls.remove(call),把异步请求从正在执行的异步请求队列中移除;
步骤2: 调用promoteCalls(),调整任务队列,由于线程不安全,所以加上synchronized同步代码块;
-- 进入promoteCalls() 其中的操作就是遍历异步等待请求队列readyAsyncCalls.iterator(),移除最后一个请求任务(i.remove())并加至异步执行队列(runningAsyncCalls.add(call))并执行(execute(call))。
步骤3: 调用runningCallsCount(),重新计算在执行的线程数量;
-- 进入runningCallsCount() 返回的就是正在执行的异步请求和正在执行的同步请求之和。
- 步骤1: 调用