设计模式之Singleton(单态/单例)
Singleton(单态 / 单例)保证一个 Class 在 Java 应用里只有一个实例。建目录、拿数据库连接这类希望全局唯一的资源,常用它。
单例可以带状态:多个单态凑在一起就像状态仓库。例如论坛帖子计数器,每次浏览加 1,用 synchronize 保证安全;若要持久化到数据库,可以在不改对外接口的前提下加上。也可以做成无状态的工具。限制实例个数还能省内存,有利于 GC。工厂、类装入器里也常见,因为被装入的类本身就是资源。
一、饿汉式:类加载时就建好
二、懒汉式:第一次用才 new
外部一律 Singleton.getInstance()。第二种是 lazy initialization:第一次调用才构造。这里的 synchronized 很重要,去掉就可能拿到多个实例。懒汉还有 double-checked locking(DCL)等讨论,一般认为第一种(饿汉)更安全些。
| 形式 | 实例何时创建 | 注意 |
|---|---|---|
| 饿汉 | 类加载时 | 实现简单,一般更安全 |
| 懒汉 | 首次 getInstance() |
必须同步,否则可能多实例 |
| DCL | 仍想懒加载又少加锁 | 细节多,需了解内存模型后再用 |
三、容器与分布式下的陷阱
多个类装入器各自装一份、或 EJB 跨服务器跨 JVM 时,Singleton 不一定“全进程只有一个”。
SUN 宠物店 Pet Store 1.3.1 的 ServiceLocator 就是例子:EJB 目录和 WEB 目录各有一份,内容差不多,都做 EJB 查询定位。WEB 侧采用 Singleton(资源定位理应单例);EJB 侧单例已经失效,所以拆成面向 WEB 和面向 EJB 两种。
模式看起来简单,要用好需要对类、线程、内存有相当了解。若应用跑在容器里,Singleton 宜少用或改用容器提供的替代方案。
一句话总结:要全局一个实例就用 Singleton:饿汉更稳,懒汉必须同步;跨 ClassLoader / 跨 JVM 时别假定全世界真的只有一份。
转载请注明来源:设计模式之Singleton(单态/单例)







