多例模式需用私有构造+静态计数器+getInstance控制实例总数,核心是私有构造、static计数、getInstance拦截;须线程安全且区分复用与销毁语义。

用静态计数器 + 私有构造 + getInstance 控制实例总数
Java 里没有语言级的“多例”关键字,得靠自己锁住构造和管理实例池。核心就三点:构造函数私有化、用静态变量记当前数量、在 getInstance() 里做数量拦截。
常见错误是把计数器放在实例里(比如用 this.count++),结果每次 new 都重置;或者忘了同步,在多线程下计数错乱,瞬间突破上限。
- 必须用
private static int instanceCount,不是实例字段 - 如果要求线程安全,
getInstance()方法得加synchronized,或用AtomicInteger - 上限值建议抽成
private static final int MAX_INSTANCES = 3,别硬写数字
为什么不用单例模式简单改一改?
单例只允许一个实例,而多例要支持「固定个数」且「可复用」——比如最多 3 个连接对象,用完一个就回收进池子再分配,不是每次都要新建。直接套单例模板,容易误写成“只创建一次”,失去复用能力。
典型踩坑:在 getInstance() 里判断 instance == null 就 new,否则 return,这其实是“懒汉单例变体”,不是多例。
立即学习“Java免费学习笔记(深入)”;
- 真正多例需要维护一个集合(如
private static List<myclass> pool</myclass>) - 首次调用时按需填充到上限,后续从池里取空闲实例
- 注意“空闲”怎么定义:是无状态?还是提供
reset()方法清空内部数据?
用枚举实现固定数量多例(适合无状态场景)
如果实例完全无状态、不保存运行时数据,枚举是最简方案——JVM 保证枚举常量初始化一次,且天然不可继承、不可反射绕过。
但注意:枚举实例不能动态增减,数量在编译期就定死;而且每个枚举常量是独立对象,没法共享状态或统一配置。
- 写法示例:
public enum ConnectionPool { INSTANCE_1, INSTANCE_2, INSTANCE_3; } - 调用时用
ConnectionPool.INSTANCE_1,不是getInstance() - 不适合需要传参初始化、或运行时决定数量的场景
销毁实例后要不要归还到池中?
多例不是单例,也不等同于对象池,关键看业务语义:如果“实例用完即弃”,那就不归还,只限制创建上限;如果希望复用以减少 GC 压力,就得设计回收机制。
最容易被忽略的是回收时机——没人主动调 release(),又没引用,GC 会直接收走,池子就“漏”了。所以得配合弱引用、Cleaner 或显式生命周期管理。
- 简单场景:让使用者调
pool.release(instance),并在线程安全下移出池 - 复杂场景:用
WeakReference包装池中实例,配合ReferenceQueue捕获回收事件 - 别指望 finalize(),它已废弃且不保证执行










