okhttp实现连接池原理

为啥需要

对于tcp/ip的网络请求,是短连接请求,每次理论上是需要三次握手和四次挥手的。频繁的进行建立Sokcet连接和断开Socket是非常消耗网络资源和浪费时间的。

然后HTTP的keep-alive也是用来优化的连接的。

  • 普通的HTTP请求是客户端连接到服务端了,请求结束后关闭连接。流程是反复的。
  • 带keep-alive头HTTP请求,服务端接受到这个字段,在一定的时间内,会维持这次连接,这期间的请求不会再次连接,而是直接复用了。

由此可见网络请求的优化是至关重要的。而okhttp则是采用连接池进行复用,减少连接的创建和关闭,增加系统负载能力。

如何实现

先说结论:OkHttp里面使用ConnectionPool实现连接池,而且默认支持5个并发KeepAlive,默认链路生命为5分钟。

先看初始化位置,okhttp采用的构建者模式创建的,其中build方法有如下:

 public Builder() {dispatcher = new Dispatcher();protocols = DEFAULT_PROTOCOLS;connectionSpecs = DEFAULT_CONNECTION_SPECS;eventListenerFactory = EventListener.factory(EventListener.NONE);proxySelector = ProxySelector.getDefault();if (proxySelector == null) {proxySelector = new NullProxySelector();}cookieJar = CookieJar.NO_COOKIES;socketFactory = SocketFactory.getDefault();hostnameVerifier = OkHostnameVerifier.INSTANCE;certificatePinner = CertificatePinner.DEFAULT;proxyAuthenticator = Authenticator.NONE;authenticator = Authenticator.NONE;//创建默认连接池,也可以指定其他参数connectionPool = new ConnectionPool();dns = Dns.SYSTEM;followSslRedirects = true;followRedirects = true;retryOnConnectionFailure = true;callTimeout = 0;connectTimeout = 10_000;readTimeout = 10_000;writeTimeout = 10_000;pingInterval = 0;}

跟进看ConnectionPool构造方法:

  /*** 使用适合于单用户应用程序的调整参数创建一个新的连接池。 *此池中的调整参数可能会在将来的OkHttp版本中更改。当前*该池最多可容纳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);// Put a floor on the keep alive duration, otherwise cleanup will spin loop.if (keepAliveDuration <= 0) {throw new IllegalArgumentException("keepAliveDuration <= 0: " + keepAliveDuration);}}

构造中默认设置了并发数量为5个,默认存活时间为5分钟。

再看下类中静态的变量,随着类创建一起创建的,如下:

/*** 后台线程用于清除过期的连接。每个连接池最多只能运行一个*线程。线程池执行程序允许对池本身进行*垃圾收集。*/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));

这里就是创建了一个线程池,只会执行一种线程,是用来执行连接池清理任务的。任务执行内容等会再看。
类中还有个关键的全局变量,双端队列Deque,双端都能进出,用来存储连接的:

  private final Deque<RealConnection> connections = new ArrayDeque<>();

再来说下是如何实现的:

  • put函数:
void put(RealConnection connection) {assert (Thread.holdsLock(this));if (!cleanupRunning) {//没有连接的时候调用cleanupRunning = true;executor.execute(cleanupRunnable);}connections.add(connection);}

RealConnection是双端队列connections存放的连接,先判断是否在锁状态后,继续判断是否在清理状态,cleanupRunning首先初始化是false值,也是无连接时候。执行cleanupRunnable只会在无连接、空闲或者使用时才会把cleanupRunning置成false,因为放入的连接后,连接池可能超出最大规定容量或者存在存活时间超时情况,所以要执行cleanupRunnable。最后会将这次连接放入双端队列中。

  • get函数
 @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;}

遍历队列集合,获取匹配且可用的连接并返回,没有则返回null。

  • cleanup函数
    前面提到的线程池来执行的任务,就是不停的调用cleanupRunnable来清楚线程池。
    先看Runnable执行代码块:
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方法会返回休眠时间,让出cpu节省资源。
cleanup方法:

  /*** 在此池上执行维护,如果超过了“保持活动”限制或“空闲连接”限制,则驱逐最长的空闲连接。  <p>以nanos为单位返回睡眠时间,直到下一次计划调用此方法为止。如果不需要进一步清理,则返回-1* -1 不需要进一步处理*/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();// 如果连接在使用,则跳过继续寻找,inUseConnectionCount++if (pruneAndGetAllocationCount(connection, now) > 0) {//使用计数inUseConnectionCount++;continue;}//空闲计数idleConnectionCount++;// 如果准备好退出连接,那么我们就完成了。long idleDurationNs = now - connection.idleAtNanos;if (idleDurationNs > longestIdleDurationNs) {longestIdleDurationNs = idleDurationNs;longestIdleConnection = connection;}}//上面是找到了最长空闲时间连接//keepAliveDurationNs  是构造定义的最大维持存活时间//maxIdleConnections  是构造定义的最大存活数量if (longestIdleDurationNs >= this.keepAliveDurationNs|| idleConnectionCount > this.maxIdleConnections) {// 符合条件,就从队列移除connections.remove(longestIdleConnection);} else if (idleConnectionCount > 0) {// 如果还有连接未清除,那么现在的线程的等待休眠时间return keepAliveDurationNs - longestIdleDurationNs;} else if (inUseConnectionCount > 0) {// 所有连接都在使用中。直到我们再次运行,这至少是保持生命的持续时间。return keepAliveDurationNs;} else {// 没有连接在使用cleanupRunning = false;return -1;}}//真正的关闭socket连接closeQuietly(longestIdleConnection.socket());// Cleanup again immediately.return 0;}

那如何判断是闲置连接了?

再来看下get函数中的一句代码:streamAllocation.acquire(connection, true);

//使用此分配来保存connection。每个对此的调用必须与同一连接上对{@link #release}的调用配对。public void acquire(RealConnection connection, boolean reportedAcquired) {assert (Thread.holdsLock(connectionPool));if (this.connection != null) throw new IllegalStateException();this.connection = connection;this.reportedAcquired = reportedAcquired;connection.allocations.add(new StreamAllocationReference(this, callStackTrace));}

acquire函数,做的就是add操作。
对比看下release函数,其实是allocations移除StreamAllocationReference操作

 /** Remove this allocation from the connection's list of allocations. */private void release(RealConnection connection) {for (int i = 0, size = connection.allocations.size(); i < size; i++) {Reference<StreamAllocation> reference = connection.allocations.get(i);if (reference.get() == this) {connection.allocations.remove(i);return;}}throw new IllegalStateException();}

其中StreamAllocationReference是弱引用,RealConnection中,有一个StreamAllocation引用列表allocations。每创建一个连接,就会把连接对应的StreamAllocationReference添加进该列表中,如果连接关闭以后就将该对象移除。这样可以根据弱引用的堆栈回收信息来计数。
再看cleanup函数中,确定计数的函数pruneAndGetAllocationCount

 /***整理所有泄漏的分配,然后返回* {@code connection}上剩余的实时分配数。如果连接正在跟踪分配,但是应用程序代码已放弃分配,则分配将泄漏。泄漏检测不精确,并且依赖于垃圾收集。*/private int pruneAndGetAllocationCount(RealConnection connection, long now) {//拿到了上文提到的引用列表 allocationsList<Reference<StreamAllocation>> references = connection.allocations;for (int i = 0; i < references.size(); ) {Reference<StreamAllocation> reference = references.get(i);if (reference.get() != null) {i++;continue;}// We've discovered a leaked allocation. This is an application bug.StreamAllocation.StreamAllocationReference streamAllocRef =(StreamAllocation.StreamAllocationReference) reference;String message = "A connection to " + connection.route().address().url()+ " was leaked. Did you forget to close a response body?";Platform.get().logCloseableLeak(message, streamAllocRef.callStackTrace);//被回收了或者一些其他情况,导致StreamAllocation为null,然后从集合移除此引用references.remove(i);connection.noNewStreams = true;// 如果这是最后一次分配,则该连接可以立即驱逐。if (references.isEmpty()) {connection.idleAtNanos = now - keepAliveDurationNs;return 0;}}//返回计数的sizereturn references.size();}

这里配合前面的弱引用,完成计数。
其实可以这样理解,在上层反复调用acquire和release函数,来增加或减少connection.allocations所维持的集合的大小,到最后如果size大于0,则代表RealConnection还在使用连接,如果size等于0,那就说明已经处于空闲状态了。

怎么获取?

get函数怎么调用的,其实很简单,往上找代码就行了,简单说说。

#mermaid-svg-gwgrrvtRb7RPdgau .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-gwgrrvtRb7RPdgau .label text{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .node rect,#mermaid-svg-gwgrrvtRb7RPdgau .node circle,#mermaid-svg-gwgrrvtRb7RPdgau .node ellipse,#mermaid-svg-gwgrrvtRb7RPdgau .node polygon,#mermaid-svg-gwgrrvtRb7RPdgau .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-gwgrrvtRb7RPdgau .node .label{text-align:center;fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .node.clickable{cursor:pointer}#mermaid-svg-gwgrrvtRb7RPdgau .arrowheadPath{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-gwgrrvtRb7RPdgau .flowchart-link{stroke:#333;fill:none}#mermaid-svg-gwgrrvtRb7RPdgau .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-gwgrrvtRb7RPdgau .edgeLabel rect{opacity:0.9}#mermaid-svg-gwgrrvtRb7RPdgau .edgeLabel span{color:#333}#mermaid-svg-gwgrrvtRb7RPdgau .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-gwgrrvtRb7RPdgau .cluster text{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-gwgrrvtRb7RPdgau .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-gwgrrvtRb7RPdgau text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-gwgrrvtRb7RPdgau .actor-line{stroke:grey}#mermaid-svg-gwgrrvtRb7RPdgau .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-gwgrrvtRb7RPdgau .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-gwgrrvtRb7RPdgau #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-gwgrrvtRb7RPdgau .sequenceNumber{fill:#fff}#mermaid-svg-gwgrrvtRb7RPdgau #sequencenumber{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau #crosshead path{fill:#333;stroke:#333}#mermaid-svg-gwgrrvtRb7RPdgau .messageText{fill:#333;stroke:#333}#mermaid-svg-gwgrrvtRb7RPdgau .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-gwgrrvtRb7RPdgau .labelText,#mermaid-svg-gwgrrvtRb7RPdgau .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-gwgrrvtRb7RPdgau .loopText,#mermaid-svg-gwgrrvtRb7RPdgau .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-gwgrrvtRb7RPdgau .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-gwgrrvtRb7RPdgau .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-gwgrrvtRb7RPdgau .noteText,#mermaid-svg-gwgrrvtRb7RPdgau .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-gwgrrvtRb7RPdgau .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-gwgrrvtRb7RPdgau .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-gwgrrvtRb7RPdgau .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-gwgrrvtRb7RPdgau .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau .section{stroke:none;opacity:0.2}#mermaid-svg-gwgrrvtRb7RPdgau .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-gwgrrvtRb7RPdgau .section2{fill:#fff400}#mermaid-svg-gwgrrvtRb7RPdgau .section1,#mermaid-svg-gwgrrvtRb7RPdgau .section3{fill:#fff;opacity:0.2}#mermaid-svg-gwgrrvtRb7RPdgau .sectionTitle0{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .sectionTitle1{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .sectionTitle2{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .sectionTitle3{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-gwgrrvtRb7RPdgau .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau .grid path{stroke-width:0}#mermaid-svg-gwgrrvtRb7RPdgau .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-gwgrrvtRb7RPdgau .task{stroke-width:2}#mermaid-svg-gwgrrvtRb7RPdgau .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau .taskText:not([font-size]){font-size:11px}#mermaid-svg-gwgrrvtRb7RPdgau .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-gwgrrvtRb7RPdgau .task.clickable{cursor:pointer}#mermaid-svg-gwgrrvtRb7RPdgau .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-gwgrrvtRb7RPdgau .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-gwgrrvtRb7RPdgau .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-gwgrrvtRb7RPdgau .taskText0,#mermaid-svg-gwgrrvtRb7RPdgau .taskText1,#mermaid-svg-gwgrrvtRb7RPdgau .taskText2,#mermaid-svg-gwgrrvtRb7RPdgau .taskText3{fill:#fff}#mermaid-svg-gwgrrvtRb7RPdgau .task0,#mermaid-svg-gwgrrvtRb7RPdgau .task1,#mermaid-svg-gwgrrvtRb7RPdgau .task2,#mermaid-svg-gwgrrvtRb7RPdgau .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-gwgrrvtRb7RPdgau .taskTextOutside0,#mermaid-svg-gwgrrvtRb7RPdgau .taskTextOutside2{fill:#000}#mermaid-svg-gwgrrvtRb7RPdgau .taskTextOutside1,#mermaid-svg-gwgrrvtRb7RPdgau .taskTextOutside3{fill:#000}#mermaid-svg-gwgrrvtRb7RPdgau .active0,#mermaid-svg-gwgrrvtRb7RPdgau .active1,#mermaid-svg-gwgrrvtRb7RPdgau .active2,#mermaid-svg-gwgrrvtRb7RPdgau .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-gwgrrvtRb7RPdgau .activeText0,#mermaid-svg-gwgrrvtRb7RPdgau .activeText1,#mermaid-svg-gwgrrvtRb7RPdgau .activeText2,#mermaid-svg-gwgrrvtRb7RPdgau .activeText3{fill:#000 !important}#mermaid-svg-gwgrrvtRb7RPdgau .done0,#mermaid-svg-gwgrrvtRb7RPdgau .done1,#mermaid-svg-gwgrrvtRb7RPdgau .done2,#mermaid-svg-gwgrrvtRb7RPdgau .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-gwgrrvtRb7RPdgau .doneText0,#mermaid-svg-gwgrrvtRb7RPdgau .doneText1,#mermaid-svg-gwgrrvtRb7RPdgau .doneText2,#mermaid-svg-gwgrrvtRb7RPdgau .doneText3{fill:#000 !important}#mermaid-svg-gwgrrvtRb7RPdgau .crit0,#mermaid-svg-gwgrrvtRb7RPdgau .crit1,#mermaid-svg-gwgrrvtRb7RPdgau .crit2,#mermaid-svg-gwgrrvtRb7RPdgau .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-gwgrrvtRb7RPdgau .activeCrit0,#mermaid-svg-gwgrrvtRb7RPdgau .activeCrit1,#mermaid-svg-gwgrrvtRb7RPdgau .activeCrit2,#mermaid-svg-gwgrrvtRb7RPdgau .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-gwgrrvtRb7RPdgau .doneCrit0,#mermaid-svg-gwgrrvtRb7RPdgau .doneCrit1,#mermaid-svg-gwgrrvtRb7RPdgau .doneCrit2,#mermaid-svg-gwgrrvtRb7RPdgau .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-gwgrrvtRb7RPdgau .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-gwgrrvtRb7RPdgau .milestoneText{font-style:italic}#mermaid-svg-gwgrrvtRb7RPdgau .doneCritText0,#mermaid-svg-gwgrrvtRb7RPdgau .doneCritText1,#mermaid-svg-gwgrrvtRb7RPdgau .doneCritText2,#mermaid-svg-gwgrrvtRb7RPdgau .doneCritText3{fill:#000 !important}#mermaid-svg-gwgrrvtRb7RPdgau .activeCritText0,#mermaid-svg-gwgrrvtRb7RPdgau .activeCritText1,#mermaid-svg-gwgrrvtRb7RPdgau .activeCritText2,#mermaid-svg-gwgrrvtRb7RPdgau .activeCritText3{fill:#000 !important}#mermaid-svg-gwgrrvtRb7RPdgau .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-gwgrrvtRb7RPdgau g.classGroup text .title{font-weight:bolder}#mermaid-svg-gwgrrvtRb7RPdgau g.clickable{cursor:pointer}#mermaid-svg-gwgrrvtRb7RPdgau g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-gwgrrvtRb7RPdgau g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-gwgrrvtRb7RPdgau .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-gwgrrvtRb7RPdgau .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-gwgrrvtRb7RPdgau .dashed-line{stroke-dasharray:3}#mermaid-svg-gwgrrvtRb7RPdgau #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau .commit-id,#mermaid-svg-gwgrrvtRb7RPdgau .commit-msg,#mermaid-svg-gwgrrvtRb7RPdgau .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-gwgrrvtRb7RPdgau g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-gwgrrvtRb7RPdgau g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-gwgrrvtRb7RPdgau g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-gwgrrvtRb7RPdgau .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-gwgrrvtRb7RPdgau .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-gwgrrvtRb7RPdgau .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-gwgrrvtRb7RPdgau .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-gwgrrvtRb7RPdgau .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-gwgrrvtRb7RPdgau .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-gwgrrvtRb7RPdgau .edgeLabel text{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-gwgrrvtRb7RPdgau .node circle.state-start{fill:black;stroke:black}#mermaid-svg-gwgrrvtRb7RPdgau .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-gwgrrvtRb7RPdgau #statediagram-barbEnd{fill:#9370db}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-state .divider{stroke:#9370db}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-gwgrrvtRb7RPdgau .note-edge{stroke-dasharray:5}#mermaid-svg-gwgrrvtRb7RPdgau .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-gwgrrvtRb7RPdgau .error-icon{fill:#522}#mermaid-svg-gwgrrvtRb7RPdgau .error-text{fill:#522;stroke:#522}#mermaid-svg-gwgrrvtRb7RPdgau .edge-thickness-normal{stroke-width:2px}#mermaid-svg-gwgrrvtRb7RPdgau .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-gwgrrvtRb7RPdgau .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-gwgrrvtRb7RPdgau .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-gwgrrvtRb7RPdgau .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-gwgrrvtRb7RPdgau .marker{fill:#333}#mermaid-svg-gwgrrvtRb7RPdgau .marker.cross{stroke:#333}:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}#mermaid-svg-gwgrrvtRb7RPdgau {color: rgba(0, 0, 0, 0.75);font: ;}

发送call请求
Dispatcher分发
拦截器ConnectInterceptor处理
streamAllocation.newStream
findHealthyConnection
findConnection
Internal.instance.get
pool.get

okhttp实现连接池原理相关推荐

  1. 泥瓦匠进阶:连接池原理设计并不难

    2019独角兽企业重金招聘Python工程师标准>>> 摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘 ...

  2. 数据库:数据库的连接池原理及实现

    对于一个简单的数据库应用,由于对于数据库的访问不是很频繁.这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销.但是对于一个复杂的数据库应用,情况 ...

  3. python连接池原理_python redis之连接池的原理

    python redis之连接池的原理 什么是连接池 通常情况下, 当我们需要做redis操作时, 会创建一个连接, 并基于这个连接进行redis操作, 操作完成后, 释放连接, 一般情况下, 这是没 ...

  4. 深入理解Spring Boot数据源与连接池原理

    ​ Create by yster@foxmail.com 2018-8-2 一:开始 在使用Spring Boot数据源之前,我们一般会导入相关依赖.其中数据源核心依赖就是spring‐boot‐s ...

  5. 基于HiKariCP组件,分析连接池原理

    池塘里养:Connection: 一.设计与原理 1.基础案例 HiKariCP作为SpringBoot2框架的默认连接池,号称是跑的最快的连接池,数据库连接池与之前两篇提到的线程池和对象池,从设计的 ...

  6. 连接池原理介绍+常用连接池介绍

    下面以访问MySQL为例,执行一个SQL命令,如果不使用连接池,需要经过哪些流程. 不使用数据库连接池的步骤: TCP建立连接的三次握手 MySQL认证的三次握手 真正的SQL执行 MySQL的关闭 ...

  7. golang mysql连接池原理_redis mysql 连接池 之 golang 实现

    1 mysql 连接池代码 package lib import ( "database/sql" "fmt" "strconv" &quo ...

  8. golang mysql连接池原理_[Go] golang实现mysql连接池

    golang中连接mysql数据库,需要使用一个第三方类库github.com/go-sql-driver/mysql,在这个类库中就实现了mysql的连接池,并且只需要设置两个参数就可以实现 一般连 ...

  9. 连接池原理--文章一

    本文摘自:http://www.blog.edu.cn/user2/franlk/archives/2005/1063830.shtml 近我作了数据库JSP的频繁连接,在此给出数据库连接池的必要性, ...

  10. DBCP连接池原理分析

    DBCP连接池介绍 ----------------------------- 目前 DBCP 有两个版本分别是 1.3 和 1.4. DBCP 1.3 版本需要运行于 JDK 1.4-1.5 ,支持 ...

最新文章

  1. 重写了GD32VF103的启动脚本和链接脚本
  2. 软件工程的瀑布, 大泥球, 教堂,集市,和银弹
  3. .NET工资低?那肯定是你打开的方式不正确
  4. LeetCode 371 两个整数之和
  5. 在ASP.NET MVC中实现Select多选
  6. 要闻君说:facebook迎来“全球宕机”惊险时刻;吸引大牛!拼多多成立了技术委员会;胡晓明卸任庚接任,阿里云计算迎来法人变更...
  7. STL之inner_product
  8. jsp文件过大,is exceeding 65535 bytes limit
  9. Atitit webdav 原理详细 概念补充 2.WebDAV的优势: 一套自己定义的安全完善的身份验证机制。 穿墙 HTTPS传送数据 使用一个TCP连接传送所有文件 方便的客户端工
  10. 易语言PHP自动更新,易语言自动更新源码
  11. python神经网络图像分类,图像分类卷积神经网络
  12. vue scss 换肤
  13. 2.4 设置工作表的背景图片 [原创Excel教程]
  14. WSO2 文件上传 (CVE-2022-29464)漏洞复现
  15. SSM框架学习记录-Spring_day01
  16. SNP位点上下游序列查找1.0 2020-9-27
  17. 从零开始使用IDEA创建JAVAWEB工程
  18. 南桥芯片和北桥芯片都有什么作用
  19. CAS实现的单点登录系统
  20. Centos7中语言如何设置成中文

热门文章

  1. 远景html制造机模板,台式机ALC892制作仿冒appleHDA的教程,前置MIC自动检测。
  2. 蓝牙耳机哪个牌子好?国庆出游蓝牙耳机推荐
  3. 2008年上半年程序员考试上午真题自我汇总
  4. android webview capturepicture,Android WebView 调用系统拍照和相册
  5. Spring IOC与AOP实现原理
  6. taro更新页面数据_taroRefresh
  7. caxa 拉伸命令的使用(一次拉伸很多线)
  8. MATLAB的数据类型
  9. Java设计模式之观察者模式应用与实战
  10. 3DMax、Unity、Threejs旋转转换