单例模式的实现方式(饿汉、懒汉、DLC、枚举)

文章目录

        • 饿汉式
        • 懒汉式
        • 双重校验锁
        • 枚举

文章参考于:

  • 菜鸟教程–单例模式

饿汉式


public class Singleton_hungry {
	/*
	 * 饿汉式:一上来就初始化对象,线程安全, 容易产生垃圾对象,类加载是就初始化,浪费内存
	 */
	private static Singleton_hungry singleton = new Singleton_hungry();

	private Singleton_hungry() {
	}

	public static synchronized Singleton_hungry getInstance() {
		return singleton;
	}
}

  • 优点:没有加锁,执行效率会提高。
  • 缺点:类加载时就初始化,浪费内存。

懒汉式


public class Singleton_lazy {
	// 懒汉式:用的时候创建对象
	private static Singleton_lazy singleton;

	private Singleton_lazy() {
	}

	public static synchronized Singleton_lazy getInstance() {
		if (null == singleton) {
			singleton = new Singleton_lazy();
		}
		return singleton;
	}
}
  • 优点:第一次调用才初始化,避免内存浪费
  • 缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率

双重校验锁


public class Singleton_DCL {
	/*
	 * 采用了双锁机制,安全且在多线程情况下能保持高性能,getSingleton() 的性能对应用程序很关键
	 */
	private volatile static Singleton_DCL singleton;

	private Singleton_DCL() {
	}

	public static Singleton_DCL getSingleton() {
		if (singleton == null) {
			synchronized (Singleton_DCL.class) {
				if (singleton == null) {
					singleton = new Singleton_DCL();
				}
			}
		}
		return singleton;
	}

}

  • DCL: double-checked locking(双重锁/双重校验锁)
  • 优点:线程安全,延迟加载,效率较高
  • singleton 采用 volatile 关键字修饰也是很有必要的, singleton = new Singleton_DCL(); 这段代码其实是分
    为三步执行:
    1. 为 singleton 分配内存空间
    2. 初始化 singleton
    3. 将 singleton 指向分配的内存地址
  • 但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1->3->2。指令重排在单线程环境下不会出先问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。例如,线程 T1 执行了 1 和 3,此时 T2 调用getUniqueInstance() 后发现 uniqueInstance 不为空,因此返回 uniqueInstance,但此时 uniqueInstance 还未被初始化。使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行。

枚举


public enum Singleton {  
    INSTANCE;  
    public void whateverMethod() {  
    }  
}
  • 优点:它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
  • 缺点:当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new,可能会给其他开发人员造成困扰,特别是看不到源码的时候。(在实际工作中,很少使用)

你可能感兴趣的:(javaweb初长成)