池化技术探析 | 周末学习

481 阅读4分钟

「本文已参与 周末学习计划 ,点击查看详情」

前言

池化技术是一种很常见的编程技巧,在请求并发很大时能明显优化应用性能,降低系统频繁创建链接的资源开销。

常见的有数据库连接池、线程池、对象池等,它们的特点都是将可以复用的东西维护在一个特定的池子中,规定其最小连接数、最大连接数、阻塞队列等配置,方便进行统一管理和复用,通常还会附带一些探活机制、强制回收、监控一类的配套功能。


线程池

JDK 1.5 中引入的 ThreadPoolExecutor 就是一种线程池的实现,它有两个重要的参数: corePoolSizemaximumPoolSize ,这两个参数控制着线程池的执行过程。

它的执行原理如下:

  • 通过 execute() 提交任务时,当线程池中的线程数小于 corePoolSize 时,新提交的任务将通过创建一个新线程来执行,即使此时线程池中存在空闲线程。
  • 通过 execute() 提交任务时,当线程池中线程数量达到 corePoolSize 时,新提交的任务将被放入 workQueue 中,等待线程池中线程调度执行。
  • 通过 execute() 提交任务时,当 workQueue 已存满,且 maximumPoolSize 大于 corePoolSize 时,新提交的任务将通过创建新线程执行。
  • 当线程池中的线程执行完任务空闲时,会尝试从 workQueue 中取头结点任务执行。
  • 通过 execute() 提交任务,当线程池中线程数达到 maxmumPoolSize ,并且 workQueue 也存满时,新提交的任务由 RejectedExecutionHandler 执行拒绝操作。
  • 当线程池中线程数超过 corePoolSize ,并且未配置 allowCoreThreadTimeOut=true ,空闲时间超过 keepAliveTime 的线程会被销毁,保持线程池中线程数为 corePoolSize
  • 当设置 allowCoreThreadTimeOut=true 时,任何空闲时间超过 keepAliveTime 的线程都会被销毁。

动态线程池

可以看看这篇Java线程池实现原理及其在美团业务中的实践,你会很有启发的。


数据库连接池

此处以 Spring 默认数据库连接池 HikariCP 为例:

  • maximum-pool-size : 连接池中最大连接数(包括空闲和正在使用的连接)默认值是 10。
  • minimum-idle : 池中最小空闲连接数量,默认值 10,小于池中最大连接数。
  • pool-name : 连接池的名字。
  • auto-commit : 是否自动提交池中返回的连接。
  • idle-timeout : 空闲时间。
  • max-lifetime : 连接池中连接的最大生命周期。
  • connection-timeout : 连接超时时间。

连接策略:

  • 小于 minimum-idle : 如果当前连接数小于最小连接数,则创建新的连接处理数据库请求;如果连接池中有空闲连接则复用空闲连接;
  • 大于 minimum-idle 并且小于 maximum-pool-size : 如果空闲池中没有连接并且当前连接数小于最大连接数,则创建新的连接处理请求;
  • 大于等于 maximum-pool-size : 如果当前连接数已经大于等于最大连接数,则按照配置中设定的时间等待旧的连接可用;
  • 如果等待超过了这个设定时间则向用户抛出错误。

对象池

平时大家都是直接 new 一个对象,但是对于一些大对象、构造耗时较多的对象这样不是一个好方法,因此我们就可以使用对象池来避免上述导致的问题。

为了避免重复造轮子,采用 Apache commons-pool 来实现,ObjectPool 主要的方法如下:

  • borrowObject() : 从对象池中获取对象的方法。
  • returnObject(T obj) : 将对象返还给对象池。
  • invalidateObject(T obj) : 让对象失效。
  • addObject() : 往对象池中新增一个对象。
  • getNumIdle() : 获取当前闲置在对象池中的对象数量,即没有被拿走使用的对象数量。
  • getNumActive() : 获取已经在使用中的对象数量,即被使用者从对象池中拿走使用的数量。
  • clear() : 清空对象池中闲置的所有对象。
  • close() : 关闭对象池。

PooledObject 抽象了对象池中对象应该具备的一些属性。注意,这个对象并不是我们真正要存的对象,而是经过一层封装的对象,那么真正存放在对象池的其实都是经过封装过的对象,即 PooledObject 对象。


总结

上面的动态线程池让我有点思考,是不是可以通过字节码增强技术来隐式的强化线程池的功能,对客户端完全无感调用。


个人备注

此博客内容均为作者学习所做笔记,侵删! 若转作其他用途,请注明来源!