Java实现线程安全的单例模式

大家可以看一下普通的单例模式,里面有懒汉式和饿汉式单例模式,对后面线程安全单例模式做个铺垫。
java 单例模式

我们这讨论的是创建时的线程安全的实现。

实现1

public final class Singleton implements Serializable {
    private Singleton(){}

    private static final Singleton INSTANCE=new Singleton();

    public static Singleton getInstance() {
        return INSTANCE;
    }
    public Object readResolve{
        return INSTANCE;
    }
}
  • 1:类前加final
    是害怕有子类继承,子类的一些方法破坏单例

  • 2:我们看到如果类实现序列化接口implements Serializable,我们可以做一些什么来防止反序列化破话单例?
    public Object readResolve{
    return INSTANCE;
    }

  • 3:这里创建实例是否有线程安全问题?
    没有,private static final Singleton INSTANCE=new Singleton();有static,所以是在类加载阶段创建实例,类加载阶段会由jvm保护线程安全。

实现2:(枚举实现)

实现3

public final class Singleton implements Serializable {
    private Singleton(){}

    private static volatile Singleton instance=null;

    public static Singleton getInstance() {
        if (instance!=null){
            return instance;
        }
        synchronized (Singleton.class){
            if (instance!=null){
                return instance;
            }
            instance=new Singleton();
            return instance;
        }
    }
}
  • private static volatile Singleton instance=null;为何需要用volatile修饰?
    在这里插入图片描述
    禁止指令重排,需要volatile关键字的原因是,在并发情况下,如果没有volatile关键字,在第5行会出现问题。instance = new TestInstance();可以分解为3行伪代码

a.memory = allocate() //分配内存

b. ctorInstanc(memory) //初始化对象

c. instance = memory //设置instance指向刚分配的地址

上面的代码在编译运行时,可能会出现重排序从a-b-c排序为a-c-b。在多线程的情况下会出现以下问题。当线程A在执行第5行代码时,B线程进来执行到第2行代码。假设此时A执行的过程中发生了指令重排序,即先执行了a和c,没有执行b。那么由于A线程执行了c导致instance指向了一段地址,所以B线程判断instance不为null,会直接跳到第6行并返回一个未初始化的对象。

  • 2:为什么在synchronized代码块内在此判断一次是否为空呢?
    在这里插入图片描述
    当第二个线程来了在第一个判断空过了,synchronized这因为得不到锁,所以等在这,当第一个线程释放锁后再进入,这是就还需要判断一次是否为空。前面第一个判断是否为空是为了减少synchronized的加锁范围。
    在这里插入图片描述
    如果直接这样锁的范围有点大!

实现4

public final class Singleton implements Serializable {
    private Singleton(){}

    private static class lazy{
        static final Singleton instance=new Singleton();
    }

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

这个是在类加载时创建实例,static在类加载时JVM保护线程安全。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值