OkHttp源码解析(三)——连接池复用

1.StreamAllocation#newStream

这个方法是在连接是返回stream对象的。我们看这个方法里的这段代码。

      RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout,
          writeTimeout, connectionRetryEnabled, doExtensiveHealthChecks);
          //省略其他代码

findHealthyConnection方法返回健康的链接。我们继续跟踪代码。最后到了findConnection方法。

2.StreamAllocation#findConnection

//省略其他代码
RealConnection pooledConnection = Internal.instance.get(connectionPool, address, this);
//省略其他代码

上面的Internal.instance是啥玩意呢?这个是在OkHttpCLient的静态代码块中初始化的。我们看下他对应的get方法。

      @Override public RealConnection get(
          ConnectionPool pool, Address address, StreamAllocation streamAllocation) {
        return pool.get(address, streamAllocation);
      }

这里调用ConnectionPool的get方法返回一个RealConnection对象。

3.ConnectionPool#get

  RealConnection get(Address address, StreamAllocation streamAllocation) {
    assert (Thread.holdsLock(this));
    for (RealConnection connection : connections) {
      if (connection.allocations.size() < connection.allocationLimit
          && address.equals(connection.route().address)
          && !connection.noNewStreams) {
        streamAllocation.acquire(connection);
        return connection;
      }
    }
    return null;
  }

这样就返回了一个已经存在的同样的RealConnect对象。
streamAllocation.acquire(connection);是RealConnection的allocations增加了一个弱引用。

回到StreamAllocation的findConnection方法,,如果从连接池中拿到了RealConnection对象,就返回。否则,继续。生成一个RealConnection对象,并加入连接池。
现在我们看看健康检查是怎么回事。

4.RealConnection#isHealthy

 public boolean isHealthy(boolean doExtensiveChecks) {
    if (socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown()) {
      return false;
    }

    if (framedConnection != null) {
      return true; // TODO: check framedConnection.shutdown.
    }

    if (doExtensiveChecks) {
      try {
        int readTimeout = socket.getSoTimeout();
        try {
          socket.setSoTimeout(1);
          if (source.exhausted()) {
            return false; // Stream is exhausted; socket is closed.
          }
          return true;
        } finally {
          socket.setSoTimeout(readTimeout);
        }
      } catch (SocketTimeoutException ignored) {
        // Read timed out; socket is good.
      } catch (IOException e) {
        return false; // Couldn't read; socket is closed.
      }
    }

    return true;
  }

这里就是检查socket的各项指标是够正确,比如说socket关闭没,输入输出通道关闭没。
如果不健康的话就调用noNewStream,这里就是释放这个RealConnection所占的资源,并且从上面操作,直到返回一个可用的健康的RealConnection。加入池里没有,就创建一个新的。并将这个新的加入池中,相关代码如下。

 RealConnection newConnection = new RealConnection(selectedRoute);
    acquire(newConnection);

    synchronized (connectionPool) {
      Internal.instance.put(connectionPool, newConnection);
      this.connection = newConnection;
      if (canceled) throw new IOException("Canceled");
    }

5.ConnectionPool

public ConnectionPool() {
    this(5, 5, TimeUnit.MINUTES);
  }

恩,默认是5个链接,每个链接的存活时长为5分钟。链接池在加入第一个链接对象的时候,会启动cleanupRunnable,做清理。我们看下这个。

  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) {
            }
          }
        }
      }
    }
  };

在cleanup函数中,会根据一定的策略移除链接。其中还有很多细节,我在这里就不关注了,感兴趣的同学自己去看下他的策略吧。

你可能感兴趣的:(Android)