okHttp3 线程池
来源:互联网 发布:好看的古装网络电视剧 编辑:程序博客网 时间:2024/06/05 05:33
先来做一个简单的网络请求
Request request = new Request.Builder() .url("http://www.baidu.com") .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { } });
我们可以看到请求中使用了 client.newCall
@Override public Call newCall(Request request) { return new RealCall(this, request, false /* for web socket */); }
在 newCall 里其实返回的是 RealCall,所以 client.newCall(request).enqueue() 其实是调用 RealCall 的 enqueue 方法
@Override public void enqueue(Callback responseCallback) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } captureCallStackTrace(); client.dispatcher().enqueue(new AsyncCall(responseCallback)); }
在 client.dispatcher().enqueue() 时传入了 AsyncCall 对象,AsyncCall 是 RealCall 的内部类,实际上是一个 Runnable;
final class AsyncCall extends NamedRunnable
所以我们回头看下 client.dispatcher().enqueue(Runnable) 这个方法得处理
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { // 在运行队列 runningAsyncCalls 添加任务 runningAsyncCalls.add(call); // 这里就是线程池的处理 executorService().execute(call); } else { // 在等待队列 readyAsyncCalls 添加任务 readyAsyncCalls.add(call); } }
其中 executorService() 这个方法是创建线程池的方法,这里用到了 ThreadPoolExecutor,可以看和 newCachedThreadPool 线程池的处理基本一致,可以看下 ThreadPoolExecutor 线程池原理
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; }
SynchronousQueue 这个等待队列里是没有任务,每一个插入操作(offer)必须等待另一个线程对应的移除操作(poll),反之亦然;
在上面有个判断 if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) 如果这个不成立的时候是要把任务放在 readyAsyncCalls 里,那么我们什么时候去取这里的任务来执行呢,看下刚才说的 runnable 就是 AsyncCall
final class AsyncCall extends NamedRunnable { private final Callback responseCallback; AsyncCall(Callback responseCallback) { super("OkHttp %s", redactedUrl()); this.responseCallback = responseCallback; } String host() { return originalRequest.url().host(); } Request request() { return originalRequest; } RealCall get() { return RealCall.this; } @Override protected void execute() { boolean signalledCallback = false; try { // 网络请求的实际操作 Response response = getResponseWithInterceptorChain(); if (retryAndFollowUpInterceptor.isCanceled()) { signalledCallback = true; // onFailure 回调 responseCallback.onFailure(RealCall.this, new IOException("Canceled")); } else { signalledCallback = true; // onResponse 回调 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); } } }
看到 finally 有个 runnable 结束的处理 client.dispatcher().finished(this); 看下里面的 finished 方法
void finished(AsyncCall call) { finished(runningAsyncCalls, call, true); }
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(); } }
处理的地方在 promoteCalls 这个方法里
private void promoteCalls() { if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity. if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote. // 遍历 readyAsyncCalls,把任务取出来 for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) { AsyncCall call = i.next(); if (runningCallsForHost(call) < maxRequestsPerHost) { i.remove(); // 取出来的任务加入 runningAsyncCalls runningAsyncCalls.add(call); // 把任务放入线程池 executorService().execute(call); } if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity. } }
所以在请求任务数大于 maxRequests 并且相同 host 最大请求数大于 maxRequestsPerHost,就会把请求任务放在 readyAsyncCalls 队列里,当线程池里执行任务的 runnable 执行完任务在最后会检查 readyAsyncCalls 里有没有任务,如果有任务并且是同一个 host 就放入到线程池中执行,所以就是通过这个方法不断地从 readyAsyncCalls 队列里取出任务,对线程池里的线程进行复用。
- okHttp3 线程池
- OkHttp3
- OkHttp3
- OkHttp3
- OkHttp3
- OkHttp3
- Okhttp3
- okHttp3
- OkHttp3
- OKHttp3源码分析<CacheThreadPool线程池异步请求任务的执行>
- OkHttp3 接口回调 UI线程
- 优雅设计封装基于Okhttp3的网络框架(三):多线程下载功能核心实现 及 线程池、队列机制、终止线程解析
- OkHttp3源码分析[复用连接池]
- OkHttp3源码分析[复用连接池]
- OkHttp3源码解析05-连接池
- OkHttp3几个简单的例子和在子线程更新UI线程的方法
- OkHttp3的连接池及连接建立过程分析
- okhttp3使用
- 最长上升子序列(LIS)长度的O(nlogn)算法
- 硬十在手,别无所求【2017.6.30版本】
- 清除页面缓存效果/div布局样式
- C++Primer Plus(第六版) 第八章 第四题
- 客户相关Table
- okHttp3 线程池
- Deep Forest: Towards an Alternative to Deep Neural Networks (阅读笔记)
- Codeforces 816D Karen and Test
- Android中常见到的异常
- poj 3070
- 03 mysql中对表的操作
- IE下background连写无法解析
- Hive中数据的加载和导出
- Hibernate——flush()方法强制同步数据库