写在前面的话
严格来说,池化思想不属于23种设计模式,但也属于日常编码中,关于设计思路和解决方案的一种。
由于近期接触比较多,就顺带分享交流一下。
本系列文章:
《程序猿之设计模式实战 · 策略模式》
《程序猿之设计模式实战 · 装饰者模式》
技术简介
池化思想是一种资源管理的设计模式,旨在通过重用已创建的对象来减少资源的消耗和提高性能。通过维护一个对象池,系统可以避免频繁地创建和销毁对象,从而降低开销和提高响应速度。
核心目的归纳为四个字:资源复用。
常见运用
程序猿在日常开发中,应该都接触过 JDK 线程池、Tomcat 线程池、Druid 连接池,这些都可以被视为“池”的实现。
下面分别介绍。
JDK 线程池
JDK 提供的线程池(如 Executors 类)可以管理线程的创建和复用。
通过配置核心线程数、最大线程数、线程存活时间等参数,可以灵活控制线程的使用。
提供了多种类型的线程池,如固定大小线程池、缓存线程池、单线程池等。
适合处理大量短时间的任务,避免频繁创建和销毁线程的开销。
Tomcat 线程池
Tomcat 作为一个 Servlet 容器,使用线程池来处理请求。
线程池的配置可以在 server.xml 中进行,允许设置最大线程数、最大连接数等。
通过重用线程,Tomcat 可以高效地处理并发请求,减少延迟。
适合高并发的 Web 应用,能够有效管理请求的处理。
Druid 连接池
Druid 是一个高性能的数据库连接池,提供了连接的复用和管理。
支持监控、统计、扩展等功能,方便开发者进行性能调优。
提供了连接的有效性检查,确保连接的可用性。
适合需要频繁访问数据库的应用,能够显著提高数据库操作的效率。
字符串常量池
字符串常量池是 Java 中的一种特殊机制,用于存储字符串字面量。
当创建字符串字面量时,JVM 会首先检查常量池中是否已有相同的字符串,如果有,则直接返回该引用。
通过重用字符串对象,节省内存空间,提高性能。
适合存储大量重复的字符串,避免了重复创建相同字符串的开销。
归纳一下
上述提到的 JDK 线程池、Tomcat 线程池、Druid 连接池和字符串常量池都可以被视为“池”的实现,尽管它们的具体用途和实现方式有所不同。
- JDK 线程池:管理和复用线程,处理并发任务,减少线程创建和销毁的开销。
- Tomcat 线程池:用于处理 HTTP 请求,管理服务器的工作线程,提升 Web 应用的并发处理能力。
- Druid 连接池:管理数据库连接的创建和复用,减少连接建立的开销,提高数据库操作的效率。
- String 常量池:存储字符串字面量,避免重复创建相同字符串,节省内存。
这些都属于池化思想的应用,通过复用资源来提高性能和效率,虽然它们的具体实现和应用场景不同,但核心理念是一致的。
分析拓展
JDK 线程池
这里以JDK线程池为例,详细介绍一下,帮助理解池化思想。
详细可参考:《知识点扫盲 · 线程池基础篇》
主要先看看下方的线程池运行流程:
里面的每个判断节点和箭头指向,就体现了关于池化思想的设计。
所谓JDK线程池,就是存储了很多线程(Thread),要复用的资源也就是Thread。
线程池从编码上,利用几个核心参数,例如核心线程数、最大线程数、缓存队列、拒绝策略等,控制了线程资源的复用规律。
1、核心线程,持续活跃的线程,最直接用来复用的单位;
2、缓存队列,按需使用不同队列,针对来不及处理的任务做缓冲处理,让活跃线程的任务处理有规律可循;
3、最大线程,相当于一级兜底方案,当队列满的时候,可以增补资源,又不至于失控;
4、拒绝策略,相当于二级兜底方案,针对实际场景,选择最后的解决方案;
Tomcat 线程池
无独有偶,Tomcat 线程池又是怎么做到池化的?
其实,Tomcat 线程池的核心流程和 JDK 线程池差不多,围绕下面四个 Tomcat 参数:
1、也有核心线程、最大线程、队列等概念,拒绝策略是固定的;
2、超过核心线程数2的时候,是先会创建到最大线程,再超过才放入队列,这个和JDK线程池有一些区别;
3、队列是无限队列,但达到maxConnections的10个后,继续请求就进不来了;
4、acceptCount相当于在3的基础上,操作系统允许再接收5个请求,处于类似挂起状态;
5、再超过5个的话,该请求会提示在一定时常后超时;
总结陈词
可以看出来,虽然流程上稍有区别,但本质思路还是一致的,Druid 连接池的实现思路也大同小异。
我们如果自己要实现一个池
的话,主要学习的是这种复用的思想,至于编码细节是可以按自己的设计调整的。
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。