文章标题

这是Singleton pattern. 但是现在已经不建议这样写了。首先这没有被lazy initialization,在程序启动时(class Smarty被load)就会创建你的static instance,拖慢启动速度。

要解决lazy initialization, 就得这么写:
public class Smarty {
private static Smarty instance;
private Smarty() {}
public static Smarty getInstance() {
if(instance == null)
instance = new Smarty();
return instance;
}
}

好了,现在instance只会在第一次getInstance被call的时候被创建。但是不好意思,多线程的情况下咋办?恩,似乎应该这样:
public class Smarty {
private static Smarty instance;
private Smarty() {}

public synchronized static Smarty getInstance() {
    if(instance == null)
        instance = new Smarty();
    return instance;
}

}

看起来不错了,但是每次调用getInstance()都需要synchronized,似乎还可以改进:
public class Smarty {
private static Smarty instance;
private Smarty() {}

public static Smarty getInstance() {
    if(instance == null) {
        synchronized(Smarty.class) {
            instance = new Smarty();
        }
    }
    return instance;
}

}

这样行了吗?好像可以了,但是有个bug,十个线程都进行了null check,但都还没进入synchonized block,大家一起排队等着吃果果。于是十个Smarty排着队被产出来了。不行。那这样呢:
public class Smarty {
private static Smarty instance;
private Smarty() {}

public static Smarty getInstance() {
    if(instance == null) {
        synchronized(Smarty.class) {
            if(instance == null) {
                instance = new Smarty();
            }
        }
    }
    return instance;
}

}

你们不是排队等着进来吃果果吗?进来了我再来check一次,这下不可能产出10个了吧。看起来已经完美了,可惜还是不行。这个可能不太好理解,但是下面这一行不是atomic的操作,它实际被分成几个步骤:allocate memory, assign allocated memory to instance ref, initialize the object Smarty into the allocated memory.
instance = new Smarty();
所以说如果线程1卡在第三步那里,线程2高高兴兴滴进来拿instance了,他会拿到一个还没煮好的蛋,吃下去,完蛋了。

有个keyword,可能一般你很少用到,叫volatile:
public class Smarty {
private static volatile Smarty instance;
private Smarty() {}

public static Smarty getInstance() {
    if(instance == null) {
        synchronized(Smarty.class) {
            if(instance == null) {
                instance = new Smarty();
            }
        }
    }
    return instance;
}

}
volatile是什么鬼?看看定义:
What is the Java volatile keyword?
Essentially, volatile is used to indicate that a variable’s value will be modified by different threads.
Declaring a volatile Java variable means:
The value of this variable will never be cached thread-locally: all reads and writes will go straight to “main memory”;
Access to the variable acts as though it is enclosed in a synchronized block, synchronized on itself.
第二点,正是我们需要的,我还没煮完的鸡蛋你先别拿。

恩,终于可以了。但是,据说大部分JVM的implementation并不尊重volatile的规则。完蛋啦,搞了半天还是没法确定可以完美做singleton。

别紧张,这样写就没问题了。正确的Java Singleton 写法:
public class Smarty {
private Smarty() {}

private static class SmartyLoader {
    private static final Smarty instance = new Smarty();
}

public static Smarty getInstance() {
    return SmartyLoader.instance;
}

}
因为Inner class的loading是在它第一次被调用的时候。合着整了半天就是这么简单。

还有一种写法,Java 5之后可用:
public enum Smarty {
INSTANCE;
}
就是这么简单粗暴直接。下次碰到谁装逼说什么double locking singleton的,上去piapia俩巴掌,甩个enum过去到他脸上,瞬间B格爆满了有没有???

不客气!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值