设计模式之Singleton(单态/单例)

    |     2015年5月7日   |   设计模式   |     0 条评论   |    1506

Singleton(单态 / 单例)保证一个 Class 在 Java 应用里只有一个实例。建目录、拿数据库连接这类希望全局唯一的资源,常用它。

单例可以带状态:多个单态凑在一起就像状态仓库。例如论坛帖子计数器,每次浏览加 1,用 synchronize 保证安全;若要持久化到数据库,可以在不改对外接口的前提下加上。也可以做成无状态的工具。限制实例个数还能省内存,有利于 GC。工厂、类装入器里也常见,因为被装入的类本身就是资源。

一、饿汉式:类加载时就建好

public class Singleton {

    private Singleton() {}

    // 在自己内部定义自己的实例;private 只供内部调用
    private static Singleton instance = new Singleton();

    public static Singleton getInstance() {
        return instance;
    }
}

二、懒汉式:第一次用才 new

public class Singleton {
    private static Singleton instance = null;

    public static synchronized Singleton getInstance() {
        if (instance == null)
            instance = new Singleton();
        return instance;
    }
}

外部一律 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(单态/单例)
本文链接地址:https://ai.zhousir.top/?p=635
回复 取消