使用连接池的目的在于降低因为反复创建连接所带来的时间损耗。我们知道,TCP协议创建连接的过程是比较复杂的,因此反复创建或关闭连接显然不是一个正确的选择,我把我们可以选择连接策略大概分为以下几种情况。

  1. 单个线程,单个链接(适用于并发量较小的场合)
  2. 多个线程,单个链接(线程在单个连接上同步将导致大量线程被阻塞,影响系统响应速度)
  3. 多个线程,多个链接
    1. 每个线程创建自己的链接(开销大,速度慢)
    2. 使用连接池(√)

正因为连接的创建和销毁都比较耗时,所以使用连接池是一种比较合理的选择,因而接下来的问题就变成了如何创建一个合适的线程池,一般策略是这样的:

  1. 在系统初始化的时候创建固定数量的连接
  2. 给连接添加一定的缓冲区,当连接数量不够时我们可以优先的把操作请求放入缓冲区中,之后当有连接空闲时就去执行缓冲区中请求
  3. 如果连接已经全部在工作并且缓冲区也已经被充满,那么我们可以动态的来创建新的连接(同时增大缓冲区),我们可以使用新创建的连接来处理多于的请求,从而增加系统的灵活性
  4. 如果请求进一步增多,连接也不断的被创建直到超过了最大连接数限制,那么此时即使请求更多也不能继续创建连接了,所以此时新的请求只能等待直到有新的资源
  5. 当请求数下降时,在运行时被新创建的连接已经进入空闲状态,我们设置一个idle time,当某个连接空闲时间超出这个时间时就会被关闭而减少系统的资源占用
  6. 连接数即使被不断减少,最低也不应该小于初始连接数的大小,即系统中应该常驻一定数量的连接数而不论当前请求数如何

我自己实现了一个简单的连接池demo,完整的代码位于 https://github.com/RitterHou/resource-pool
首先需要创建一个用于模拟数据库(服务器)的类,它提供了执行一次请求的方法,在这个方法中我们假设每次执行操作都需要100ms。

我们还需要一个连接类,因为创建链接普遍比较耗时,所以我假设创建一个连接需要500ms,并且连接还需要指定一台服务器。连接还需要提供可以执行服务器命令的方法,我还记录了连接最后一次执行命令的时间来帮助记录连接的空闲时间。

有了服务器和连接之后我们就可以创建自己的连接池实现了,连接池的主要策略实现在获取归还连接的方法中。除此之外,我们还实现了自动执行超时连接关闭的方法

最后,我们就可以开始测试我们的连接池了。我创建了两个线程,分别使用单个连接和连接池来处理100个请求,观察它们的结果差异,我的运行结果如下:

[Thread-1] INFO com.nosuchfield.pool.Application - 单个启动耗时:503
[Thread-2] INFO com.nosuchfield.pool.Application - 连接池启动耗时:5005
[Timer-0] INFO com.nosuchfield.pool.Pool - 5 个连接被移除,还剩 15
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 15
[Thread-2] INFO com.nosuchfield.pool.Application - 连接池执行耗时:3932
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Thread-1] INFO com.nosuchfield.pool.Application - 单个执行耗时:10012
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 0 个连接被移除,还剩 17
[Timer-0] INFO com.nosuchfield.pool.Pool - 7 个连接被移除,还剩 10