java 单例 dcl_单例模式DCL问题

我们都知道在程序执行过程中,java虚拟机为了速率,有可能会产生重排序。拿最普通的初始化一个实例来讲。他的过程如下:

(1)分配内存;

(2)初始化实例;

(3)将实例指向该内存。

但是由于重排序的特性,可能最终的执行方式是1->3->2。如此就会产生,还没有将实例中的变量初始化完毕,就已经分配了内存。此时该实例已经不为null,但是其中的成员变量,还没有初始化为指定值。当别的线程调用时,就会返回错误的结果。

举个例子:

一般情况下,我们写一个单例模式可能会使用这种双重检查的方式;

public classSingleClass{

String a;

String b;private staticSingleClass instance;privateSingleClass(){this.a = 1;---------------------------------5this.b = 2;---------------------------------6

}public staticSingleClass newInstance(){if(instance==null){-------------------------1synchronized(SingleClass.class){---------2if(instance==null){-----------------3

instance= newinstance();------4

}

}

}returninstance;

}

}

但是当并发量高时,可能会出现上面那种情况,即线程A检查到1,但是重排序了,先将实例指向了内存地址,所以instance不再为null,他内部还没有初始化完毕,比如只初始化了a;此时线程B也调用了newInstance方法,检查到instance不为null,于是直接返回。此时返回的就是一个没有初始化b值的实例。造成数据缺失。

因此我们可以使用共享变量volatile来修饰该实例的引用。

对于volatile修饰的变量来说,禁止重排序,保障运行过程中写操作在读操作之前,如此就可以保障(1)-->(2)-->(3)的顺序,所以也不会产生上述情况了。

private static volatile SingleClass instance;

当然我们还推荐另一种方式,使用内部类的方法进行单例构造,可以从虚拟机层面保障单例啦;

静态内部类的优点是:外部类加载时并不需要立即加载内部类,内部类不被加载则不初始化instance,因此不占内存。

按照本例就是:当SingleInner第一次被加载时,并不需要去加载SingleHolder。只有当newInstance()方法第一次被调用时,才会去初始化instance,实现了惰性单例加载。

public classSingleInner{

String a;

String b;privateSingleInner(){this.a = 1;this.b = 2;

}private static classSingleHolder{private static final SingleInner instance = newInstance();

}public staticSingleInner newInstance(){returnSingleHolder.instance;

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值