OkHttp Source Code Analyse (Part one)
来源:互联网 发布:淘宝二手手机评估 编辑:程序博客网 时间:2024/06/05 14:43
OkHttp
An HTTP & HTTP/2 client for Android and Java applications
HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP efficiently makes your stuff load faster and saves bandwidth.
OkHttp is an HTTP client that’s efficient by default:
- HTTP/2 support allows all requests to the same host to share a socket.
- Connection pooling reduces request latency (if HTTP/2 isn’t available).
- Transparent GZIP shrinks download sizes.
- Response caching avoids the network completely for repeat requests.
OkHttp perseveres when the network is troublesome: it will silently recover from common connection problems. If your service has multiple IP addresses OkHttp will attempt alternate addresses if the first connect fails. This is necessary for IPv4+IPv6 and for services hosted in redundant data centers. OkHttp initiates new connections with modern TLS features (SNI, ALPN), and falls back to TLS 1.0 if the handshake fails.
Using OkHttp is easy. Its request/response API is designed with fluent builders and immutability. It supports both synchronous blocking calls and async calls with callbacks.
OkHttp supports Android 2.3 and above. For Java, the minimum requirement is 1.7.
From:http://square.github.io/okhttp/
Example:
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("www.baidu.com") .build(); //sync method Response response = client.newCall(request).execute(); //async method client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { } });
(1)client.newCall(Request request);
OkHttpClient.java
/** * Prepares the {@code request} to be executed at some point in the future. */@Override public Call newCall(Request request) { return new RealCall(this, request);}
protected RealCall(OkHttpClient client, Request originalRequest) { this.client = client; this.originalRequest = originalRequest;}
RealCall.java
@Override public void enqueue(Callback responseCallback) { enqueue(responseCallback, false);}void enqueue(Callback responseCallback, boolean forWebSocket) { synchronized (this) { if (executed) throw new IllegalStateException("Already Executed"); executed = true; } client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));}(2-1)client.dispatcher();
Dispatcher.java
private int maxRequests = 64;private int maxRequestsPerHost = 5;/** Executes calls. Created lazily. */private ExecutorService executorService;/** Ready async calls in the order they'll be run. */private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();/** Running synchronous calls. Includes canceled calls that haven't finished yet. */private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();public Dispatcher(ExecutorService executorService) { this.executorService = executorService;}public 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;}
可以看出Dispatcher内包含一个TheadPoolExecutor(线程池),负责管理并执行加入其中的任务,
重点区分下面这三个Deque:
readyAsyncCalls:等待执行的任务队列;
runningAsyncCalls:正在执行的异步任务队列;
runningSyncCalls:正在执行的同步阻塞任务队列;
(2-2) client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
Dispatcher.java
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); }}
可以看出:当向Dispather中加入新的异步任务时,如果当前正在执行的异步任务数小于64并且在所有正在执行的异步任务中与该新任务拥有相同主机名的任务小于5时,直接将该任务加入正在执行的任务队列中,并开始执行它,否则加入等待队列。
(3)线程池执行一个异步任务AsycCall(实际就是一个Runnable),会调用该类的execute()方法;
RealCall.java
@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); }}
(3-1) Response response = getResponseWithInterceptorChain(forWebSocket);
发送网络请求,并获取响应,后续会详细介绍,获取响应或出现异常 通过Callback responseCallback回调给发送请求方。
(3-2)最后会执行 client.dispatcher().finished(this);
Dispatcher.java
/** Used by {@code AsyncCall#run} to signal completion. */synchronized void finished(AsyncCall call) { if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!"); promoteCalls();}private void promoteCalls() { if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity. if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote. 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; // Reached max capacity. }}
可以看出,在finished(AsyncCall call)中将刚刚完成的AsyncCall从runningAsyncCalls中移除,然后调用promoteCalls()方法;
在promoteCalls()方法中,如果当前正在执行的任务个数大于等于64,表示线程池已经达到最大并发量,不能再加入新任务,退出。如果当前等待队列为空,表示新任务可执行,退出。
否则就遍历readyAsyncCalls,如果某个任务的主机名在正在执行的任务队列的个数小于5 ,则将其从等待队列中移除并加入到runningAsyncCalls中并放入线程池执行,直至线程池达到最大并发量64。
然后,当线程池中的某任务执行完后,再调用Dispather的finished 方法,再从等待任务队列中取出新任务加入到线程池中执行。与此同时,也会有任务不断的加入Dispather中,当线程池中有任务执行完毕后,就会从等待队列中取出任务加入到线程池中执行。
每当有任务执行完毕后,都会主动检测等待任务队列是否有可执行的任务,而没有使用互斥锁等逻辑,避免发生死锁。
作者:BlackSwift链接:http://www.jianshu.com/p/6637369d02e7來源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。OkHttp采用Dispatcher技术,类似于Nginx,与线程池配合实现了高并发,低阻塞的运行 Okhttp采用Deque作为缓存,按照入队的顺序先进先出 OkHttp最出彩的地方就是在try/finally中调用了 finished
函数,可以主动控制等待队列的移动,而不是采用锁或者wait/notify,极大减少了编码复杂性
Reference:http://www.jianshu.com/p/6637369d02e7
- OkHttp Source Code Analyse (Part one)
- DSS Source Code Analyse (01) - StartServer
- DSS Source Code Analyse (02) - select_waitevent
- DSS Source Code Analyse (03) - EventThread::Entry
- DSS Source Code Analyse (04) - TCPListenerSocket::ProcessEvent
- DSS Source Code Analyse (05) - EventContext::ProcessEvent
- DSS Source Code Analyse (06) - Task::Signal
- DSS Source Code Analyse (07) - TaskThread::Entry
- DSS Source Code Analyse (08) - EventContext::RequestEvent
- DSS Source Code Analyse (09) - RTSPSession::Run
- DSS Source Code Analyse (10) - RTPSession::Run
- DSS Source Code Analyse (11) - TimeoutTask
- DSS Source Code Analyse (19) - Authentication
- DSS Source Code Analyse (20) - HttpProxy
- DSS Source Code Analyse (21) - Filter
- DSS Source Code Analyse (23) - OSHashTable
- DSS Source Code Analyse (24) - OSHeap
- DSS Source Code Analyse (25) - OSQueue
- JS事件机制:事件绑定、事件监听、事件委托(事件代理)
- 关于HTTP协议,一篇就够了
- iexpress打包ActiveXObject报错
- 解决Ubuntu系统和Windows系统双系统时间冲突问题
- 面试题32问
- OkHttp Source Code Analyse (Part one)
- 海量数据处理
- webstorm 提示 Can't use Subversion command line client: svn
- C/C++ 第八周串和数组 (一)建立顺序串的算法库 项目1
- Intent.使用小结
- java分布式电子商务云平台b2b b2c o2o需要准备哪些技术??
- 我们为什么要造自动驾驶汽车?它到底有什么用?
- 构建linux根文件系统(六)终结
- ActiveMQ消息传送机制以及ACK机制详解