java 安全发布_Java中安全发布和安全初始化

该文主要将Java的单例和JMM内存管理以及同步锁性能综合起来考虑,对传统Double-Checked Locking 提出了进一步完善,并用Intel芯片和ARM芯片分别进行了测试。从文中看出,在多线程中做好单例值的初始化真不是一件简单的事情,也许因为单例和多线程在概念上本身不匹配吧。

传统的DCL单例代码如下:

public class UnsafeDCLFactory {

private Singleton instance;//问题在这里,应该让其他线程看到instance是否被初始化public Singleton get() {

if (instance == null) {// check 1synchronized (this) {

if (instance == null) {// check 2instance = new Singleton();

}

}

}

return instance;

}

}

这段代码其实在多线程环境并没有安全发布。所谓安全发布需要以下几个约束:

1. 使用静态的初始化器进行初始化

2.通过一个适当加锁字段交换引用

3.通过一个volatile或AtomicX字段交换引用

4.使用final标识字段,initialize the value into a final field (JLS 17.5). Caveat emptor:只对之前没有其他人看到过的对象有效,对于已经发布的对象使用final已经太迟了。

对于UnsafeDCLFactory显然有以下问题:

1.并没有使用静态初始化器

2.至少有一个单例读是不受锁保护的

3.单例没有通过volatile 字段发布

4.单例也没有通过final字段发布.

重构如下:

public class SafeDCLFactory {

private volatile Singleton instance;

public Singleton get() {

if (instance == null) { // check 1synchronized(this) {

if (instance == null) {// check 2instance = new Singleton();

}

}

}

return instance;

}

}

该文还提出了使用初始化器发布单例的方式,通常我们使用下面静态初始化器来实现(单例的另外一种实现)

public class HolderFactory {

public static Singleton get() {

return Holder.instance;

}

private static class Holder {

public static final Singleton instance = new Singleton();

}

}

这段代码直到第一次调用get()方法,Holder才被初始化,但是因为是在构造器以外使用了final字段,这太迟了,得用一个wrapper包裹一下,以确保没有人看到过单例:

public class FinalWrapperFactory {

private FinalWrapper wrapper;

public Singleton get() {

FinalWrapper w = wrapper;

if (w == null) { // check 1synchronized(this) {

w = wrapper;

if (w == null) {// check2w = new FinalWrapper(new Singleton());

wrapper = w;

}

}

}

return w.instance;

}

private static class FinalWrapper {

public final Singleton instance;

public FinalWrapper(Singleton instance) {

this.instance = instance;

}

}

}

该文最后还讨论了使用使用加锁字段实现单例的安全发布:

public class SafeLocalDCLFactory implements Factory {

private volatile Singleton instance;

@[author]Override[/author]

public Singleton getInstance() {

Singleton res = instance;

if (res == null) {

synchronized (this) {

if (instance == null) {

instance = new Singleton();

}

}

return instance;

}

return res;

}

}

关于安全初始化,文章推荐使用final字段,参考All Fields Are Final (banq注:这实际是不变性的值对象)

有关在Intel和ARM芯片上测试参考原文,点击标题可进入。

[该贴被banq于2014-10-15 10:54修改过]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值