Okhttp任务队列工作原理
2016-08-24 16:23
411 查看
应用层:
1.讲请求添加到分发起中 Client.dispatcher().executed(this);
2.创建截获器ApplicationInterceptorChain(可对请求进行压缩,修改编码等处理)
逻辑层
1.数据缓存:
1)缓存的数据没有过期,直接使用
2)缓存的数据过期,先用过期的,再去网络请求数据,并更新本地数据
3)缓存的数据没有,去网络直接获取
2.底层使用连接池
3.路线选择器(路由选择,选择最优)
4.网络截获器可以有多个(依据目标地址是否有重定向来觉得)
链路层
1.底层是Socket
1 概述
1.1 线程池ThreadPoolExecutor
ThreadPoolExecutor是java线程创建工具。存在于java.util.concurrent 包中。
看构造方法:
corePoolSize : 最小并发线程数。
maximumPoolSize :线程池中最大的线程池并发数。
keepAliveTime : 当线程的数目大于
corePoolSize时,线程的最大存活时间。
unit : 时间单位 BlockingQueue 工作队列
okhttp的线程池对象存在于Dispatcher类中。实例过程如下:
1.2 Call对象
okttp的操作元是Call对象。异步的实现是RealCall.AsyncCall。而 AsyncCall是实现的一个Runnable接口。所以Call本质就是一个Runable线程操作元肯定是放进excutorService中直接启动的。
2.2 过程分析
Call代用enqueue方法的时候
方法中满足执行队列里面不足最大线程数maxRequests并且Call对应的host数目不超过maxRequestsPerHost 的时候直接把call对象直接推入到执行队列里,并启动线程任务(Call本质是一个Runnable)。否则,当前线程数过多,就把他推入到等待队列中。Call执行完肯定需要在runningAsyncCalls 队列中移除这个线程。那么readyAsyncCalls队列中的线程在什么时候才会被执行呢。
追溯下AsyncCall 线程的执行方法
这里做了核心request的动作,并把失败和回复数据的结果通过responseCallback 回调到Dispatcher。执行操作完毕了之后不管有无异常都会进入到dispactcher的finished方法。
在这里call在runningAsyncCalls队列中被移除了,重新计算了目前正在执行的线程数量。并且调用了promoteCalls() 看来是来调整任务队列的
原来实在这里对readyAsyncCalls 进行调度的。最终会在readyAsyncCalls 中通过remove操作把最后一个元素取出并移除之后加入到runningAsyncCalls的执行队列中执行操作。ArrayDeque 是非线程安全的所以finished在调用promoteCalls 的时候都在synchronized块中执行的。执行等待队列线程当然的前提是runningAsyncCalls 线程数没有超上线,而且等待队列里面有等待的任务。
小结,Call在执行任务通过Dispatcher把单元任务优先推到执行队列里进行操作,如果操作完成再执行等待队列的任务。
1.讲请求添加到分发起中 Client.dispatcher().executed(this);
2.创建截获器ApplicationInterceptorChain(可对请求进行压缩,修改编码等处理)
逻辑层
1.数据缓存:
1)缓存的数据没有过期,直接使用
2)缓存的数据过期,先用过期的,再去网络请求数据,并更新本地数据
3)缓存的数据没有,去网络直接获取
2.底层使用连接池
3.路线选择器(路由选择,选择最优)
4.网络截获器可以有多个(依据目标地址是否有重定向来觉得)
链路层
1.底层是Socket
1 概述
1.1 线程池ThreadPoolExecutor
ThreadPoolExecutor是java线程创建工具。存在于java.util.concurrent 包中。
看构造方法:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
corePoolSize : 最小并发线程数。
maximumPoolSize :线程池中最大的线程池并发数。
keepAliveTime : 当线程的数目大于
corePoolSize时,线程的最大存活时间。
unit : 时间单位 BlockingQueue 工作队列
okhttp的线程池对象存在于Dispatcher类中。实例过程如下:
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; }
1.2 Call对象
okttp的操作元是Call对象。异步的实现是RealCall.AsyncCall。而 AsyncCall是实现的一个Runnable接口。所以Call本质就是一个Runable线程操作元肯定是放进excutorService中直接启动的。
final class AsyncCall extends NamedRunnable {}
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>(); private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
2.2 过程分析
Call代用enqueue方法的时候
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } }
方法中满足执行队列里面不足最大线程数maxRequests并且Call对应的host数目不超过maxRequestsPerHost 的时候直接把call对象直接推入到执行队列里,并启动线程任务(Call本质是一个Runnable)。否则,当前线程数过多,就把他推入到等待队列中。Call执行完肯定需要在runningAsyncCalls 队列中移除这个线程。那么readyAsyncCalls队列中的线程在什么时候才会被执行呢。
追溯下AsyncCall 线程的执行方法
@Override protected void execute() { boolean signalledCallback = false; try { Response response = getResponseWithInterceptorChain(forWebSocket); if (canceled) { signalledCallback = true; responseCallback.onFailure(RealCall.this, new IOException("Canceled")); } else { signalledCallback = true; responseCallback.onResponse(RealCall.this, response); } } catch (IOException e) { if (signalledCallback) {// Do not signal the callback twice! Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e); } else { responseCallback.onFailure(RealCall.this, e); } } finally { client.dispatcher().finished(this); } }
这里做了核心request的动作,并把失败和回复数据的结果通过responseCallback 回调到Dispatcher。执行操作完毕了之后不管有无异常都会进入到dispactcher的finished方法。
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) { int runningCallsCount; Runnable idleCallback; synchronized (this) { if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!"); if (promoteCalls) promoteCalls(); runningCallsCount = runningCallsCount(); idleCallback = this.idleCallback; } if (runningCallsCount == 0 && idleCallback != null) { idleCallback.run(); } }
在这里call在runningAsyncCalls队列中被移除了,重新计算了目前正在执行的线程数量。并且调用了promoteCalls() 看来是来调整任务队列的
private void promoteCalls() { if (runningAsyncCalls.size() >= maxRequests) return; // if (readyAsyncCalls.isEmpty()) return; for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { AsyncCall call = i.next(); if (runningCallsForHost(call) < maxRequestsPerHost) { i.remove(); runningAsyncCalls.add(call); executorService().execute(call); } if (runningAsyncCalls.size() >= maxRequests) return; } }
原来实在这里对readyAsyncCalls 进行调度的。最终会在readyAsyncCalls 中通过remove操作把最后一个元素取出并移除之后加入到runningAsyncCalls的执行队列中执行操作。ArrayDeque 是非线程安全的所以finished在调用promoteCalls 的时候都在synchronized块中执行的。执行等待队列线程当然的前提是runningAsyncCalls 线程数没有超上线,而且等待队列里面有等待的任务。
小结,Call在执行任务通过Dispatcher把单元任务优先推到执行队列里进行操作,如果操作完成再执行等待队列的任务。
相关文章推荐
- Okhttp任务队列工作原理
- OkHttp 3.7源码分析(三) - 任务队列
- OkHttp3源码分析[任务队列]
- OkHttp 3.7源码分析(三)——任务队列
- OkHttp 3.7源码分析(三)——任务队列
- OkHttp 3.7源码分析(三)——任务队列
- OkHttp3源码分析[任务队列]
- OkHttp3源码分析[任务队列]
- 用Redis实现分布式锁 与 实现任务队列
- vxworks中任务间的通信支持信号量、消息队列、管道、信号、事件、共享内存等
- celery分布式队列任务
- 中断处理的tasklet(小任务)机制和workqueue(工作队列)机制
- 进程/多线程/同步任务/异步任务/串行队列/并行队列
- 分布式任务队列与任务调度系统Celery入门
- 使用Redis实现任务队列
- Celery - 分布式任务队列
- go 任务队列执行超时
- celery 任务队列初步探索
- rabbitmq-任务轮询队列
- ios-day19-02(GCD介绍。串行队列、并行队列、全局队列、主队列、同步任务、异步任务)