移动开发最新Android 网络性能优化(3)复用连接池,2024年最新阿里巴巴p8面试

最后

下面是辛苦给大家整理的学习路线

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  1. SSL连接池

管理SSLSocket,但SSLSocket又依赖于TCP连接池提供的TCPSocket

  1. HTTP代理连接池

如果走HTTP协议,那么就需要TCP连接池提供TCPSocket,如果走HTTPS协议,那么就需要SSL连接池提供SSLSocket;

  1. SpdySession池

依赖SSL连接池提供SSLSocket,这里需要说明下,虽然HTTP/2协议没有强制绑定HTTPS,但是在实际开发中确实都是绑定HTTPS

  1. SOCKS连接池

管理的SOCKSSocket和SOCKS5Socket都需要依赖TCP连接池提供的TCPSocket

  1. WebSocket连接池

依赖TCP连接池提供的TCPSocket,声明下这里没有说明WSS(Web Socket Secure)的情况

3. 源码实现

=========================================================================

这里参考的是OkHttp4的代码

3.1 ConnectionPool类


连接池的类位于okhttp3.ConnectionPool。我们需要了解到如何在timeout时间内复用connection,并且有效的对其进行回收清理操作。我们先来看看该类的作用,因为有文档注释,我们来看看官方是如何描述该类的

在这里插入图片描述

翻译:该类管理 Http/Http2 的连接复用,用来减少网络的消耗。有着相同ip地址的Http请求可以共享一个连接通道。该类实现了一种长连接的策略。

构造函数创造了一个新的连接池和附带参数,这些参数可能会在未来的OkHttp版本中被更改(也就是说不建议我们直接使用)。目前这个连接池可以最多同时持有5个闲置的连接,如果有多的连接,将会被移除掉。

// ConnectionPool.kt

class ConnectionPool internal constructor(

internal val delegate: RealConnectionPool

) {

constructor(

maxIdleConnections: Int,

keepAliveDuration: Long,

timeUnit: TimeUnit

) : this(RealConnectionPool(

taskRunner = TaskRunner.INSTANCE,

maxIdleConnections = maxIdleConnections,

keepAliveDuration = keepAliveDuration,

timeUnit = timeUnit

))

// 1

constructor() : this(5, 5, TimeUnit.MINUTES)

}

这是构造函数,注释1中可以看出,默认就的最多闲置连接是5个,保持时间是5分钟,taskRunner是一个线程管理器,用来检测闲置socket并对其进行清理,在3.x版本中,它是一个Executor。然后这个类就没别的东西了,其他的都在它的父类RealConnectionPool里面了

3.2 RealConnectionPool的缓存操作


RealConnectionPool是真正的连接池,ConnectionPool是其子类,他除了刚刚那几个子类传来的参数之外,还有一个很重要的参数:

/**

  • 使用线程安全的双向队列来管理所有的 [RealConnection]—Socket连接

*/

private val connections = ConcurrentLinkedQueue()

连接池可以通过 connections来管理连接的添加、删除、复用。

3.2.1 put操作

fun put(connection: RealConnection) {

connection.assertThreadHoldsLock()

// 1

connections.add(connection)

// 2

cleanupQueue.schedule(cleanupTask)

}

注释1: 在连接池connections中添加一个连接。

注释2: 需要整理一遍connections里的连接,比如说多出来的连接需要删除掉,超过保持时长的连接要去掉。

3.2.2 判断连接是否可以复用

在3.x版本,该类提供了一个方法来返回一个可复用的连接,主要逻辑是遍历connections的所有连接,判断是否有连接可复用。而4.x的版本稍微的更改逻辑,先来看下这个方法:

// 1

fun callAcquirePooledConnection(

address: Address,

call: RealCall,

routes: List?,

requireMultiplexed: Boolean

): Boolean {

for (connection in connections) {

synchronized(connection) {

// 2

if (requireMultiplexed && !connection.isMultiplexed) return@synchronized

// 3

if (!connection.isEligible(address, routes)) return@synchronized

// 4

call.acquireConnectionNoEvents(connection)

return true

}

}

return false

}

注释1: 传入一个ip地址,该方法就是判断是否已经存在该ip打通的socket,如果有返回true,说明可以复用,否则返回false

注释2: 判断连接的多路复用,这个属性是给Http2用的

注释3: 检查ip地址和路由列表是否合法

注释4: 调用 RealCall.acquireConnectionNoEvents()方法,将RealCall的 connection指向该连接,表明存在可以复用的连接,并且返回true。那么调用者就可以通过它的RealCall来获取到复用的连接了。

可以看下 RealCall的方法:

// RealCall.kt

fun acquireConnectionNoEvents(connection: RealConnection) {

connection.assertThreadHoldsLock()

check(this.connection == null)

this.connection = connection

connection.calls.add(CallReference(this, callStackTrace))

}

3.2.3 清除和回收连接

在刚刚put方法里面,我们看到了该类会实现一个方法来check连接池里的连接,它的作用是清除和回收超时和多出来的连接,我们来看看这个方法,因为方法比较长,所以分成两个部分来看,下面是上半部分:

// RealConnectionPool.kt

/**

  • 作用是维护连接池,删除那些超时的连接、或者超出最大数量限制的连接

  • 返回的值是睡眠到下次执行该方法的时间,

  • 如果不需要进一步清理,则返回-1

*/

fun cleanup(now: Long): Long {

var inUseConnectionCount = 0

var idleConnectionCount = 0

var longestIdleConnection: RealConnection? = null

var longestIdleDurationNs = Long.MIN_VALUE

// 1

for (connection in connections) {

synchronized(connection) {

// 2

if (pruneAndGetAllocationCount(connection, now) > 0) {

inUseConnectionCount++

} else {

idleConnectionCount++

// 3

val idleDurationNs = now - connection.idleAtNs

if (idleDurationNs > longestIdleDurationNs) {

longestIdleDurationNs = idleDurationNs

longestIdleConnection = connection

} else {

Unit

}

}

}

}

}

注释1: 遍历连接池内的所有连接

注释2: 调用 pruneAndGetAllocationCount()方法,查看该连接是否正在被使用。如果正在使用,则工作连接+1,否则 闲置连接+1

注释3: 计算该连接的闲置时间。遍历一圈,记录下闲置时间最久的连接。

再来看下cleanup()的下半部分:

// RealConnectionPool.kt

when {

// 1

longestIdleDurationNs >= this.keepAliveDurationNs

|| idleConnectionCount > this.maxIdleConnections -> {

val connection = longestIdleConnection!!

synchronized(connection) {

if (connection.calls.isNotEmpty()) return 0L // No longer idle.

if (connection.idleAtNs + longestIdleDurationNs != now) return 0L // No longer oldest.

connection.noNewExchanges = true

(longestIdleConnection)

}

connection.socket().closeQuietly()

if (connections.isEmpty()) cleanupQueue.cancelAll()

// Clean up again immediately.

return 0L

}

// 2

idleConnectionCount > 0 -> {

return keepAliveDurationNs - longestIdleDurationNs

}

// 3

inUseConnectionCount > 0 -> {

return keepAliveDurationNs

总结

找工作是个很辛苦的事情,而且一般周期都比较长,有时候既看个人技术,也看运气。第一次找工作,最后的结果虽然不尽如人意,不过收获远比offer大。接下来就是针对自己的不足,好好努力了。

最后为了节约大家的时间,我把我学习所用的资料和面试遇到的问题和答案都整理成了PDF文档

喜欢文章的话请关注、点赞、转发 谢谢!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

找工作是个很辛苦的事情,而且一般周期都比较长,有时候既看个人技术,也看运气。第一次找工作,最后的结果虽然不尽如人意,不过收获远比offer大。接下来就是针对自己的不足,好好努力了。

最后为了节约大家的时间,我把我学习所用的资料和面试遇到的问题和答案都整理成了PDF文档

喜欢文章的话请关注、点赞、转发 谢谢!

[外链图片转存中…(img-AJVTPBta-1715434612869)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 29
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值