转载请以链接形式标明出处:
本文出自:103style的博客
base on 3.12.0
目录
- 简介
ConnectionPool的成员变量ConnectionPool的构造函数ConnectionPool的相关方法- 小结
简介
ConnectionPool 即连接池,用来管理 HTTP 和 HTTP/2 连接的重用,以减少网络延迟。
相同的 HTTP 请求可以共用一个连接(RealConnection), ConnectionPool 实现了将哪些连接保持打开状态以备将来使用的策略。
即 ConnectionPool 是用来管理 RealConnection 用的。
ConnectionPool 的成员变量
- 用于清除过期的连接,每个连接池最多只能运行一个线程。
线程池执行程序允许对池本身进行垃圾回收。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)); - 最大空闲连接数,在
cleanup(...)清理的时候用到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()); if (waitNanos == -1) return; if (waitNanos > 0) { long waitMillis = waitNanos / 1000000L; waitNanos -= (waitMillis * 1000000L); synchronized (ConnectionPool.this) { try { ConnectionPool.this.wait(waitMillis, (int) waitNanos); } catch (InterruptedException ignored) { } } } } } }; - 保存可复用连接的队列
private final Deque<RealConnection> connections = new ArrayDeque<>(); - 连接地址要避免的失败路由黑名单
final RouteDatabase routeDatabase = new RouteDatabase(); - 是否是清理过期连接的标记位
boolean cleanupRunning;
ConnectionPool 的构造函数
默认配置的 每个地址的空闲连接数为 5个,每个空闲连接的存活时间为 5分钟.
public ConnectionPool() {
this(5, 5, TimeUnit.MINUTES);
}
public ConnectionPool(int maxIdleConnections, long keepAliveDuration, TimeUnit timeUnit) {
this.maxIdleConnections = maxIdleConnections;
this.keepAliveDurationNs = timeUnit.toNanos(keepAliveDuration);
if (keepAliveDuration <= 0) {
throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);
}
}
ConnectionPool 的相关方法
公开方法
-
public synchronized int idleConnectionCount()
获取当前空闲连接的个数public synchronized int idleConnectionCount() { int total = 0; for (RealConnection connection : connections) { if (connection.allocations.isEmpty()) total++; } return total; } -
public synchronized int connectionCount()
获取当前连接的个数public synchronized int connectionCount() { return connections.size(); } -
public void evictAll()
关闭和移除连接池中所有的空闲连接public void evictAll() { List<RealConnection> evictedConnections = new ArrayList<>(); synchronized (this) { for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) { RealConnection connection = i.next(); if (connection.allocations.isEmpty()) { connection.noNewStreams = true; evictedConnections.add(connection); i.remove(); } } } for (RealConnection connection : evictedConnections) { closeQuietly(connection.socket()); } }
私有方法
-
RealConnection get(Address address, StreamAllocation streamAllocation, Route route)
获取可复用的连接,没有则返回null.@Nullable RealConnection get(Address address, StreamAllocation streamAllocation, Route route) { assert (Thread.holdsLock(this)); for (RealConnection connection : connections) { if (connection.isEligible(address, route)) { streamAllocation.acquire(connection, true); return connection; } } return null; } -
Socket deduplicate(Address address, StreamAllocation streamAllocation)
如果可能,将streamAllocation保留的连接替换为共享连接。@Nullable Socket deduplicate(Address address, StreamAllocation streamAllocation) { assert (Thread.holdsLock(this)); for (RealConnection connection : connections) { if (connection.isEligible(address, null) && connection.isMultiplexed() && connection != streamAllocation.connection()) { return streamAllocation.releaseAndAcquire(connection); } } return null; } -
void put(RealConnection connection)
先清除过期的连接,再将可复用的连接保存到队列connections中void put(RealConnection connection) { assert (Thread.holdsLock(this)); if (!cleanupRunning) { cleanupRunning = true; executor.execute(cleanupRunnable); } connections.add(connection); } -
boolean connectionBecameIdle(RealConnection connection)
告诉连接池,connection已变为空闲连接。
如果配置了RealConnection.noNewStreams= true 不允许复用或者maxIdleConnections==0 不允许有空闲连接,则直接从队列中删除该连接。boolean connectionBecameIdle(RealConnection connection) { assert (Thread.holdsLock(this)); if (connection.noNewStreams || maxIdleConnections == 0) { connections.remove(connection); return true; } else { notifyAll(); return false; } } -
long cleanup(long now)
清除过期的空闲连接。1.0循环遍历connections主要是寻找队列中 正在使用的连接inUseConnectionCount、空闲连接的个数idleConnectionCount、空闲等待最久的连接longestIdleConnection2.0空闲等待最久的连接等待时间超过了keepAliveDurationNs,或者 空闲连总数大于了允许的最大空闲连接数maxIdleConnections,则从队列中移除当前连接,并关闭,然后cleanupRunnable继续执行cleanup(long now).3.0如果有空闲的连接,则cleanupRunnable等待时间为keepAliveDurationNs - longestIdleDurationNs4.0如果连接都在使用中,则cleanupRunnable等待时间为keepAliveDurationNs5.0否则cleanupRunnable任务完成
long cleanup(long now) { int inUseConnectionCount = 0; int idleConnectionCount = 0; RealConnection longestIdleConnection = null; long longestIdleDurationNs = Long.MIN_VALUE; synchronized (this) { // 1.0 for (Iterator<RealConnection> i = connections.iterator(); i.hasNext(); ) { RealConnection connection = i.next(); if (pruneAndGetAllocationCount(connection, now) > 0) { inUseConnectionCount++; continue; } idleConnectionCount++; long idleDurationNs = now - connection.idleAtNanos; if (idleDurationNs > longestIdleDurationNs) { longestIdleDurationNs = idleDurationNs; longestIdleConnection = connection; } } if (longestIdleDurationNs >= this.keepAliveDurationNs || idleConnectionCount > this.maxIdleConnections) { //2.0 connections.remove(longestIdleConnection); } else if (idleConnectionCount > 0) {//3.0 return keepAliveDurationNs - longestIdleDurationNs; } else if (inUseConnectionCount > 0) {//4.0 return keepAliveDurationNs; } else {//5.0 cleanupRunning = false; return -1; } } closeQuietly(longestIdleConnection.socket());//关闭连接 return 0; }
小结
-
连接池
ConnectionPool是用来管理HTTP和HTTP/2连接的重用,以减少网络延迟。 -
连接池默认时每个地址的空闲连接数为 5个,每个空闲连接的存活时间为 5分钟.
-
连接池每次添加一个新的连接时,都会先清理当前连接池中过期的连接,通过 清理线程池
executor执行清理任务cleanupRunnable。
以上
本文深入探讨了OkHttp中的ConnectionPool组件,详细介绍了其管理HTTP和HTTP/2连接的策略,包括成员变量、构造函数及关键方法。ConnectionPool旨在通过重用连接减少网络延迟,每个地址默认维护5个空闲连接,每个连接存活5分钟。
4845

被折叠的 条评论
为什么被折叠?



