java单例模式正确创建方式

现在在网络上搜索“java单例模式”关键词,很容易能够得到所谓的“懒汉式”,“饿汉式”两种模式。

//饿汉式
public class SingletonDemo {
    private static SingletonDemo instance=new SingletonDemo();
    private SingletonDemo(){

    }
    public static SingletonDemo getInstance(){
        return instance;
    }
}
//懒汉式
public class SingletonDemo {
    private static SingletonDemo instance;
    private SingletonDemo(){

    }
    public static synchronized SingletonDemo getInstance(){
        if(instance==null){
            instance=new SingletonDemo();
        }
        return instance;
    }
}
//懒汉式进阶(双重检查)
public class SingletonDemo {
    private static SingletonDemo instance;
    private SingletonDemo(){
        System.out.println("Singleton has loaded");
    }
    public static SingletonDemo getInstance(){
        if(instance==null){
            synchronized (SingletonDemo.class){
                if(instance==null){
                    instance=new SingletonDemo();
                }
            }
        }
        return instance;
    }
}

实际上第3种“双重检查”的单例模式不一定正确,下面是分析。

if(instance==null){//1
            synchronized (SingletonDemo.class){//2
                if(instance==null){//3
                    instance=new SingletonDemo();//4
                }
            }
        }

上面代码块的前1,2,3,4步操作其实大家都能理解,能够答复降低synchronized带来的性能开销,但是操作4可以分解为如下的3行伪代码:

memory = allocate();//1.分配对象的内存空间
ctorInstance(memory);//2.初始化对象
instance = memory();//3.设置instance指向刚分配的内存地址

以上3步操作在一些JIT编译器上是会被重排序的,也就是说可能的执行顺序为1—>3—>2,当对象还未初始化的时候instance已经指向了对象的内存空间,此时instance!=null,这很重要!在多线程环境下,线程A中出现了指令重排,当执行到步骤2之前,线程B开始执行到if(instance==null)语句,此时由于instance!=null,返回instance对象,但是该对象还未初始化,所以线程B得到的对象依然为空!

注意:该种情况只会发生在多线程并发环境,单线程环境不会发生,因为在单线程中,只需要保证初次访问对象在初始化对象之后即可,无需在意2,3操作是否会发生重排!


解决方法:

public class SingletonDemo {
    private volatile static SingletonDemo instance;//注意该行的变化
    private SingletonDemo(){
        System.out.println("Singleton has loaded");
    }
    public static SingletonDemo getInstance(){
        if(instance==null){
            synchronized (SingletonDemo.class){
                if(instance==null){
                    instance=new SingletonDemo();
                }
            }
        }
        return instance;
    }
}

这个解决方案需要JDK1.5或更高版本(因为从JDK5开始使用新的JSR-133内存模型规范,这个规范增强了volatile的语义)
当声明对象的引用为volatile后,上面2,3步操作的重排序在多线程环境下将会被禁止,其执行步骤将会按如下时序执行:
这里写图片描述

以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值