当前位置:编程学习 > JAVA >>

单例模式的一个疑问

网上很多关于单例模式写法的文章,不外乎饿汉和懒汉两种形式的讨论。很多人喜欢用懒汉式,因为觉得它实现了延迟加载,可以让系统的性能更好。但事实果真如此吗?我对此存疑。

首先我们检查一下饿汉和懒汉单例模式最简单的写法(这里不讨论哪种懒汉写法更好):

// 饿汉
public final class HungrySingleton {
    private static final HungrySingleton INSTANCE = new HungrySingleton();
 
    private HungrySingleton() {
        System.out.println("Initializing...");
    }
 
    public static HungrySingleton getInstance() {
        return INSTANCE;
    }
}
 
// 懒汉
public final class LazySingleton {
    private static LazySingleton INSTANCE;
 
    private LazySingleton() {
        System.out.println("Initializing...");
    }
 
    public static synchronized LazySingleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new LazySingleton();
        }
        return INSTANCE;
    }

从理论上来说,HungrySingleton 的单例在该类第一次使用的时候创建,而 LazySingleton 的单例则在其 getInstance() 方法被调用的时候创建。至于网上有人声称“饿汉式不管用不用都会初始化”,纯属走路的时候步子迈得太大。谁的加载更迟?如果你只是调用它们的 getInstance() 方法来得到单例对象,则它们都是延迟加载,这样懒汉式没有任何意义,而且由于 LazySingleton 采取了同步措施,性能更低(可以说任何懒汉式的性能都低于饿汉式)。当你使用一个单例类的时候,难道第一步不是调用 getInstance() 么?所以在自己的代码里,我更喜欢用饿汉式。

下面用一个例子来测试加载顺序:

// 饿汉
System.out.println("Before");
HungrySingleton.getInstance();
System.out.println("After");
 
// 懒汉
System.out.println("Before");
LazySingleton.getInstance();
System.out.println("After"); 

输出结果都是:

Before
Initializing...
After
那么,懒汉模式还有什么存在意义?如果系统使用了某些需要在启动时对类进行扫描的框架,使用饿汉式的话,启动时间比懒汉式更长,如果使用了大量单例类,不利于开发阶段。在系统的正式运行阶段,所有的单例类迟早都要加载的,总的说来两者性能持平,但是懒汉式每次都至少多一个判断,所以越到后期越体现饿汉的优越性。

最后,推荐下《Effective Java》第二版指出的用枚举类型实现的饿汉单例模式:

 // 饿汉
public enum HungrySingleton {
    INSTANCE;
 
    private HungrySingleton() {
    }
}

这种写法不但最简洁,还能轻易扩展为实例数量固定的“多例模式”。

 

摘自 神奇好望角
 
补充:软件开发 , Java ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,