单例模式的线程不安全问题

1.单例模式

  • 懒汉模式 :线程不安全,多线程下可能new多个Test类。
public class Test {
    private Test() {
    }
    private static Test instance = null;
    public static Test getInstance() {
        if (instance == null) {
            instance = new Test();
        }
        return instance;
    }
}
  • 饿汉模式 :线程安全,但是当类加载时,就new实例对象了,不符合懒加载模式。
public class Test {
    private Test() {
    }

    private static Test instance = new Test();

    public static Test getInstance() {
        return instance;
    }
}
  • 懒汉模式-加锁 :线程安全,方法上加锁严重影响性能。第二次直接取instance值都加锁了。
public class Test {
    private Test() {
    }
    private static Test instance = null;
    public static synchronized Test getInstance() {
        if (instance == null) {
            instance = new Test();
        }
        return instance;
    }
}
  • 懒汉模式-双重锁机制 :线程不安全。由于指令重排。
public class Test {
    private Test() {
    }
    private static Test instance = null;
    public static Test getInstance() {
        if (instance == null) { // 双重检测机制
            synchronized (Test.class) {
                if (instance == null) {
                    instance = new Test(); 
                }
            }
        }
        return instance;
    }
}

instance = new Test()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
  1. 给 instance 分配堆内存(Test 对象)
  2. 调用 Test的构造函数来初始化成员变量,形成实例
  3. 将instance 指针 指向分配的内存空间(执行完这步 singleton才是非 null了)。
正常执行顺序:1->2->3,由于操作2和操作3没有依赖性(操作1和操作3有依赖性),可能发生指令重排,可能的执行顺序为:1->3->2。
回到代码,当操作1,3执行后,instnce指针是不为null了,此时,另一个线程执行 if(instance == null) 就会不成立,直接返回,而此时,Single的构造还可能未执行,会引发严重数据错误!!!!

  • 懒汉模式-双重锁机制+volatile:线程安全。volatile禁止了指令重排。
public class Test {
    private Test() {
    }
    private volatile static Test instance = null;
    public static Test getInstance() {
        if (instance == null) { // 双重检测机制
            synchronized (Test.class) {
                if (instance == null) {
                    instance = new Test(); 
                }
            }
        }
        return instance;
    }
}
  • 枚举单利:线程安全。最优解。
public class Test {
    private Test() {
    }

    public static Test getInstance() {
        return Singleton.INSTANE.getIntance();
    }

    private enum Singleton {
        INSTANE;
        private Test singleton;
        Singleton() {
            singleton = new Test();
        }
        public Test getIntance() {
            return singleton;
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值