源码阅读--OkHttp3
来源:互联网 发布:java zxing 二维码 编辑:程序博客网 时间:2024/05/17 00:17
用法在这里
http://blog.csdn.net/itachi85/article/details/51190687
大致流程如下:
1.准备OkHttpClient
2.准备requestBuilder
3.mOkHttpClient.newCall(request).enqueue
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));//-------------------- }
dispatcher的enqueue实现如下:
synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call);//------------------执行网络操作 } else { readyAsyncCalls.add(call); } }
流程没什么难度。接下来看一下OkHttpClient的实现
ConnectionPool
OkHttpClient是通过Builder来实现的,也就是建造者模式,里面有一个重要的数据结构ConnectionPool
public final class ConnectionPool { //-------------------------ThreadPoolExecutor,我以前的blog有讲过 private static final Executor executor = new ThreadPoolExecutor(0 /* corePoolSize */, Integer.MAX_VALUE /* maximumPoolSize */, 60L /* keepAliveTime */, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp ConnectionPool", true)); //-----------------------------------最大空闲连接 private final int maxIdleConnections; private final long keepAliveDurationNs; private final Runnable cleanupRunnable = new Runnable() { @Override public void run() { while (true) { long waitNanos = cleanup(System.nanoTime());//----------------------//如果空闲连接keepAlive时间超过5分钟,或者空闲连接数超过5个,则从Deque中移除此连接 if (waitNanos == -1) return; if (waitNanos > 0) { long waitMillis = waitNanos / 1000000L; waitNanos -= (waitMillis * 1000000L); synchronized (ConnectionPool.this) { try { //------------------------------wait在waitMillis毫秒后还有等待os调用分配资源,所以停止运行时间是不确定的,但至少是waitMillis毫秒。 ConnectionPool.this.wait(waitMillis, (int) waitNanos); } catch (InterruptedException ignored) { } } } } } }; private final Deque<RealConnection> connections = new ArrayDeque<>();//---------------------------------下面有解释(核心) final RouteDatabase routeDatabase = new RouteDatabase();//------------------------------------------LinkedHashSet,HashSet的子类,说白了就是LinkedHashMap boolean cleanupRunning; //----------------------------默认构造函数,其实构造函数里面就对部分参数赋值 public ConnectionPool() { this(5, 5, TimeUnit.MINUTES); } public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) { this.maxIdleConnections = maxIdleConnections; this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration); // Put a floor on the keep alive duration, otherwise cleanup will spin loop. if (keepAliveDuration <= 0) { throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration); } } //------------------------遍历connections缓存列表,当某个连接计数的次数小于限制的大小并且request的地址和缓存列表中此连接的地址完全匹配,则直接复用缓存列表中的connection RealConnection get(Address address, StreamAllocation streamAllocation, Route route) { assert (Thread.holdsLock(this)); for (RealConnection connection : connections) { if (connection.isEligible(address, route)) { streamAllocation.acquire(connection); return connection; } } return null; } void put(RealConnection connection) { assert (Thread.holdsLock(this)); if (!cleanupRunning) { cleanupRunning = true; executor.execute(cleanupRunnable);//-----------------------清理线程 } connections.add(connection); } //--------------------------------------------//如果空闲连接keepAlive时间超过5分钟,或者空闲连接数超过5个,则从Deque中移除此连接 long cleanup(long now) { int inUseConnectionCount = 0; int idleConnectionCount = 0; RealConnection longestIdleConnection = null; long longestIdleDurationNs = Long.MIN_VALUE; synchronized (this) { for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) { RealConnection connection = i.next(); // If the connection is in use, keep searching. if (pruneAndGetAllocationCount(connection, now) > 0) {//----------里面有Reference,用来计数的 inUseConnectionCount++; continue; } idleConnectionCount++; // If the connection is ready to be evicted, we're done. long idleDurationNs = now - connection.idleAtNanos; if (idleDurationNs > longestIdleDurationNs) { longestIdleDurationNs = idleDurationNs; longestIdleConnection = connection; } } if (longestIdleDurationNs >= this.keepAliveDurationNs || idleConnectionCount > this.maxIdleConnections) { // We've found a connection to evict. Remove it from the list, then close it below (outside // of the synchronized block). connections.remove(longestIdleConnection);//----------------------//如果空闲连接keepAlive时间超过5分钟,或者空闲连接数超过5个,则从Deque中移除此连接 } else if (idleConnectionCount > 0) { return keepAliveDurationNs - longestIdleDurationNs; } else if (inUseConnectionCount > 0) { return keepAliveDurationNs; } else { cleanupRunning = false; return -1; } } closeQuietly(longestIdleConnection.socket()); // Cleanup again immediately. return 0; }}
ArrayDeque的解释:
有三个重要的数据结构
private transient E[] elements; private transient int head; private transient int tail;
很明显,类似于链表。其中的数组元素在add等方法执行时不移动,发生变化的只是head和tail指针。
头指针head从0开始,尾指针tail从n开始,在头部插入数据时,head减一,在尾部插入数据时,tail加一。(取余,所以是循环)
当head==tail时说明数组的容量满足不了当前的情况,此时需要扩大容量为原来的二倍。
0 0
- 源码阅读--OkHttp3
- OkHttp3源码阅读1之同步和异步请求的实现
- OkHttp3源码阅读2之请求和响应数据的解析
- OkHttp3源码分析
- OkHttp3源码分析[综述]
- OkHttp3 源码解读
- OkHttp3源码学习简要
- okHttp3源码简要分析
- okhttp3 源码深入分析
- Okhttp3源码解析
- Okhttp3源码浅析
- OkHttp3源码分析[综述]
- OkHttp3源码分析[DiskLruCache]
- OkHttp3 源码解读
- OkHttp3源码解析
- okhttp3 源码分析
- 关于OkHttp3源码分析
- OkHttp3源码解析
- 100个直接可以拿来用的JavaScript实用功能代码片段
- 顺序表原子操作的实现(C语言)
- AI不可怕,就怕AI会画画——这里有一种你还不知道的‘图’灵测试…
- LeetCode117 Populating Next Right Pointers in Each Node II
- 技术男留存的好网站,再此收藏!
- 源码阅读--OkHttp3
- 火焰图相关的一些东西
- CodeForces 798A Mike and palindrome
- #HDU3435#A new Graph Game(环+KM)
- Ubuntu输入su提示认证失败的解决方法
- 编译原理(1)
- 数据库的水平分割和垂直分割
- leetcode:Jump Game II
- PHP设计模式系列(二十一):享元模式