懒汉式单例模式的安全问题

懒汉式单例模式的安全问题

//懒汉式单例模式
public class LazySingleton {
    
    private LazySingleton() {
        // TODO Auto-generated constructor stub
    }
    
    private static LazySingleton lazySingleton = null;
    
    /**
     * 只声明,先不创建对象
     * @return
     */
    public LazySingleton getSingleton() {
        if(lazySingleton==null) {
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }
    
    public String getAccount(){
        return "公司账户";
    }

}

如果在上述代码的情况下,在其他类中获取了该对象。但是,把该对象重定向,指向了某自定义对象,如下:

public class MySingleton extends LazySingleton{
    public String getAccount(){
        return "我的账户";
    }
}

是否会造成严重安全问题?

除了把“LazySingleton"设为”final"外,还有其他解决方案吗?还是说这种模式先天存在这个缺陷?

你 new 的还是 LazySingleton 啊, 并不是 MySingleton, 所以 MySingleton 并不会影响到 LazySingleton 的使用

【以下回答由 GPT 生成】

这种情况会造成严重的安全问题。由于懒汉式单例模式在多线程环境下存在竞态条件(race condition),当多个线程同时通过getSingleton()方法来获取单例对象时,可能会创建多个实例,从而破坏了单例模式的特性。

除了把LazySingleton类设置为final外,还有其他解决方案来解决这个问题:

  1. 使用同步方法:可以在getSingleton()方法上加上synchronized关键字,确保在多线程环境下只有一个线程能够访问该方法,从而避免了并发创建实例的问题。但是这样会降低性能,因为每次调用getSingleton()都会获取锁。
public synchronized LazySingleton getSingleton() {
    if(lazySingleton==null) {
        lazySingleton = new LazySingleton();
    }
    return lazySingleton;
}
  1. 使用双重检查加锁(double-checked locking):在synchronized块内进行第二次判断,如果实例已经创建,则无需再获取锁。
public LazySingleton getSingleton() {
    if(lazySingleton==null) {
        synchronized (LazySingleton.class) {
            if(lazySingleton==null) {
                lazySingleton = new LazySingleton();
            }
        }
    }
    return lazySingleton;
}
  1. 使用静态内部类:可以使用静态内部类来实现懒汉式单例模式,静态内部类在第一次被使用时才会被加载,可以保证单例的实例化过程在多线程环境下的安全性。
public class LazySingleton {

    private LazySingleton() {
        // TODO Auto-generated constructor stub
    }

    private static class SingletonHolder {
        private static final LazySingleton INSTANCE = new LazySingleton();
    }

    public static LazySingleton getSingleton() {
        return SingletonHolder.INSTANCE;
    }

    public String getAccount(){
        return "公司账户";
    }

}


【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^