Java 23 种设计模式:从踩坑到精通 | 番外:享元 vs 对象池 —— 不可变共享 vs 可变复用
Java 23 种设计模式从踩坑到精通 | 番外享元 vs 对象池 —— 不可变共享 vs 可变复用摘要享元模式和对象池模式都能减少对象创建、节约内存但享元的核心是不可变对象的共享——相同内部状态的客户端拿到的是同一个只读实例对象池的核心是可变对象的复用——客户端借出、用完归还对象状态随时变化。本文从字符共享和数据库连接池两个场景出发结合代码对比、UML 分析和Integer.valueOf()、HikariCP 等 JDK 源码帮你彻底分清这对“池化型”模式。️本文阅读地图3 分钟速览为什么字符共享是享元连接池是对象池UML 对比不可变共享 vs 借还复用手写享元工厂 vs 对象池看代码感受差异JDKInteger.valueOf()享元vs 数据库连接池对象池源码分析面试必问“享元和对象池怎么区分连接池是享元吗”《Java 23 种设计模式从踩坑到精通》开篇系列介绍与目录 当前番外 · 享元 vs 对象池 返回系列总目录文章目录Java 23 种设计模式从踩坑到精通 | 番外享元 vs 对象池 —— 不可变共享 vs 可变复用1. 从“字符共享”和“连接池”两个场景说起1.1 场景一文本编辑器字符共享享元模式1.2 场景二数据库连接池对象池模式1.3 关键差异已浮现2. UML 对比3. 三大核心区别4. JDK 源码深度对比4.1 Integer.valueOf()享元模式4.2 HikariCP 数据库连接池对象池模式5. 什么时候不该用6. 面试必问 追问连环炮 《Java 23 种设计模式从踩坑到精通》快速导航1. 从“字符共享”和“连接池”两个场景说起1.1 场景一文本编辑器字符共享享元模式一篇十万字的文章如果每个字符都new一个Character对象内存会迅速撑爆。享元模式的思路将字符对象的状态分为内部状态字符、字体、字号——不可变、可共享和外部状态行列位置——由客户端管理。享元工厂维护一个池每种内部状态只创建一个实例。// 享元工厂每种内部状态只创建一个不可变实例publicclassCharacterFactory{privatestaticfinalMapString,TextCharacterpoolnewConcurrentHashMap();publicstaticTextCharactergetCharacter(charsymbol,Stringfont,intsize){Stringkeysymbol_font_size;returnpool.computeIfAbsent(key,k-newConcreteCharacter(symbol,font,size));}}// 客户端11 个字符只创建了 8 个享元实例l 和 o 重复TextCharacterc1CharacterFactory.getCharacter(l,Arial,12);// 新创建TextCharacterc2CharacterFactory.getCharacter(l,Arial,12);// 复用和 c1 是**同一个对象**System.out.println(c1c2);// true白话享元池中的对象是“只读”的——创建后就不能修改。客户端只是拿来用用完不用归还。多个客户端拿到的是同一个实例。1.2 场景二数据库连接池对象池模式数据库连接对象是有状态、可变的。一个连接可能处于“空闲”、“已借用”、“已关闭”等状态。对象池的运作方式客户端从池中借一个空闲连接用完后归还池负责管理连接的生命周期。// HikariCP 对象池简化示例HikariDataSourcedataSourcenewHikariDataSource(config);// 客户端1借一个连接Connectionconn1dataSource.getConnection();// 从池中借出conn1.setAutoCommit(false);// 修改连接状态// ... 执行业务操作 ...conn1.close();// 归还给池// 客户端2借一个连接可能是同一个物理连接但状态已重置Connectionconn2dataSource.getConnection();// 从池中借出System.out.println(conn1conn2);// false不同对象或状态已重置的同一对象白话对象池中的对象是“借出-归还”模式。借出时可能被修改状态归还时池会重置状态如回滚事务、清理上下文。多个客户端拿到的是不同的实例或状态已被重置的实例。1.3 关键差异已浮现享元对象创建后就不可变多个客户端共享同一个实例不用归还对象池对象可变客户端借出→使用→归还池负责状态管理。2. UML 对比3. 三大核心区别对比维度享元模式对象池模式对象可变性不可变创建后不能修改可变借出后状态可能被修改共享方式相同 key 返回同一个实例为 true借出不同的实例用完归还生命周期管理常驻内存一般不销毁借出→使用→归还→可销毁空闲超时典型应用Integer.valueOf(-128~127)、字符串常量池数据库连接池HikariCP、线程池核心特征只读共享外部状态由客户端管理复用归还状态由池管理4. JDK 源码深度对比4.1Integer.valueOf()享元模式// Integer 对 -128~127 范围的整数进行了缓存// 范围内的整数共享同一个不可变 Integer 实例IntegeraInteger.valueOf(100);IntegerbInteger.valueOf(100);System.out.println(ab);// true同一个对象IntegercInteger.valueOf(200);IntegerdInteger.valueOf(200);System.out.println(cd);// false超出缓存范围新建对象为什么是享元Integer对象不可变final class没有 setter相同值的整数返回同一个实例在缓存范围内客户端只是“拿来用”用完不需要归还内部状态整数值是可共享的外部状态无由客户端管理。4.2 HikariCP 数据库连接池对象池模式// HikariCP 是典型的对象池模式HikariConfigconfignewHikariConfig();config.setJdbcUrl(jdbc:mysql://localhost:3306/mydb);config.setMaximumPoolSize(10);// 最大连接数config.setIdleTimeout(600000);// 空闲超时 10 分钟HikariDataSourcedataSourcenewHikariDataSource(config);// 借出连接ConnectionconndataSource.getConnection();// 使用连接可能修改状态设置事务隔离级别、超时等conn.setAutoCommit(false);// 归还连接由池重置状态conn.close();为什么是对象池Connection对象可变状态包括是否自动提交、事务隔离级别、超时等每次getConnection()返回的是不同实例或状态已被重置的实例客户端必须归还调用close()归还给池而非真正关闭池管理对象生命周期最大连接数、空闲超时、连接验证。5. 什么时候不该用滥用场景应该用什么原因对象状态需要频繁修改如连接对象池享元要求对象不可变状态可变会导致数据污染对象创建成本低数量不大直接 new池化增加代码复杂度收益不大对象不可变且只有少量种类享元对象池管理复杂度高不需要借还逻辑线程复用线程池对象池变体线程是有状态、可变的不是不可变共享6. 面试必问 追问连环炮基础必问享元和对象池有什么区别→ 享元共享不可变对象相同 key 返回同一实例对象池复用可变对象借出-归还模式。数据库连接池是享元模式吗→不是。连接池是对象池模式。连接对象有状态、可变需要借出和归还。面试官追问“Integer.valueOf()是享元模式那String.intern()呢” 也是享元模式。intern()将字符串放入常量池相同内容的字符串共享同一个不可变实例。“对象池中的对象归还时为什么要重置状态” 防止上一个使用者的状态污染下一个使用者。例如归还连接时需要回滚未提交的事务、清除临时表、重置隔离级别。“如果享元对象的内部状态被意外修改了会怎样”数据污染事故。A 客户端修改了共享对象B 客户端拿到的是脏数据。因此享元对象必须设计为不可变final字段 无 setter这是享元模式最致命的踩坑点。“线程池是享元还是对象池” 对象池。线程是有状态的运行/阻塞/等待借出后状态不断变化用完归还回池中。ThreadLocal 可以用来给每个线程分配独立的上下文但线程本身是对象池管理的。恭喜如果你能立刻说出Integer.valueOf()是享元不可变共享、数据库连接池是对象池可变复用并理解“享元对象必须不可变”的原因你已经掌握了这对“池化型”模式的核心区分点。延伸阅读本文是享元模式与对象池模式的深度对比。如果你想先了解享元模式的完整原理、UML、代码实现和面试题可以先阅读正篇——享元模式内存吃不消试试共享细粒度对象再回来看这篇对比效果更佳。 《Java 23 种设计模式从踩坑到精通》快速导航开篇系列介绍与目录当前番外 · 享元 vs 对象池 —— 不可变共享 vs 可变复用你在这里 延伸阅读享元模式正篇创建型模式汇总结构型模式汇总行为型模式汇总 关注《Java 23 种设计模式从踩坑到精通》用 25 篇文章彻底吃透设计模式。福利预告全系列代码及 UML 源码将在完结时统一打包开放点击「关注」「收藏」第一时间获取。 除了设计模式我也在深挖智能物流实战WMS、托盘调度、机器学习落地。欢迎点击头像看看专栏 《出版社物流WMS智能调度实战》。技术相通思路可鉴。

相关新闻