OkHttp连接池

391 阅读2分钟

连接池 ConnectionPool

ConnectionPool的get方法

  • 从连接池中获取一个Connection并检查是否可用(isEligible),可用则调用acquire
    -- 进入streamAllocation.acquire
  • 把从连接池中获取到的RealConnection对象赋给StreamAllocation的connection成员变量(this.connection)。
  • 把StreamAllocation的弱引用添加到RealConnection的allocations(ArrayList)集合中,通过这个集合判断StreamAllocation的个数,进而判断一个网络连接的负载量是否已经超过OkHttp指定的最大值(最大连接数)。

ConnectionPool的put方法

  • 做完异步清理任务后,添加连接connection至connections(ArrayDeque)。
  • cleanupRunnable用于回收connection(见下)。

  • 每次http请求都会产生一个StreamAllocation对象,不管在哪个拦截器中产生的。

Connection的自动回收流程

  1. 利用GC回收算法
  2. 当连接(StreamAllocation)的数量变为0时,会被线程池ConnectionPool检测到
  3. ConnectionPool中有个独立的线程会开启cleanupRunnable来清理连接池。

-- 进入cleanupRunnable

  • while(true)死循环阻塞。
  • 首次清理会返回下次清理的间隔时间waitNanos。
  • cleanup中使用了GC回收算法。
  • 调用ConnectionPool.this.wait等待释放锁和时间片,等待时间过后会再次调用cleanupRunnable去清理(while(true)),同时返回下次要清理的时间waitNanos。
    -- 进入cleanup
    1. 遍历队列中所有的RealConnection,类似Java中标记清除算法,首先标记出最不活跃的connection连接(空闲连接)。
    2. 若被标记的连接满足一定条件,如空闲的Socket连接超过5个,则将其(longestIdleConnection)从连接中删除,并关闭连接。
    3. 若全都是活跃连接(idleConnectionCount > 0),则keepAliveDurationNs - longestIdleDurationNs时间后再次清理。
    4. 若有正在使用的连接(inUseConnectionCount > 0),则返回keepAliveDurationNs时间供下次清理使用。
    5. 没有任何连接时返回-1,跳出while(true)死循环。
    • Q: 如何找到最不活跃的连接?
      Ans: pruneAndGetAllocationCount方法遍历弱引用集合,根据弱引用是否为null,为null表示没有代码引用该对象,则删除它(references.remove(i))。