-
除了饿汉式和懒汉式,还有其他的比较优雅的实现方式。
-
单例模式的多线程其实是由懒加载模式引起的。
-
直接给获取实例的方法加锁,这样效率极其慢,直接串行化了。
public class Singleton1 {
private static Singleton1 instance;
private Singleton1() {
}
public synchronized static Singleton1 getInstance(){
if (null == instance)
instance = new Singleton1();
return Singleton1.instance;
}
}
- double-check(两次是否为null判断)。减少锁的争取。但是这有一个比较难想到的bug。有可能会出现空指针异常。原因:在new instance执行完毕后,实例不为空了。但是可能上面的构造的函数运行慢,加载了外部很多的东西。而另一条线程因为判断不为空了,直接用实例中的东西,但因为构造函数并没有执行好,所以会抛出空指针异常。这里Singleton2要加上volatile才是完整版本,与有序性有关
public class Singleton2 {
private static Singleton2 instance;
private Singleton2(){
//假设此时构造函数加载了很多东西,花费时间很长。
}
//double check
public static Singleton2 getInstance(){
if(null == instance){
synchronized (Singleton2.class) {
if (null == instance)
instance = new Singleton2();
}
}
return Singleton2.getInstance();
}
}
三种比较优雅的实现方式
- private static Singleton2 instance 在volatile关键字。这个关键字确保,你要读之前,前面的写操作一定要全部执行完。告诉JVM不要擅自优化。与happens-before有关。不过不让优化的代价就是速度慢
- 静态内部类
public class Singleton3 {
private Singleton3() {
}
private static class InstanceHolder {
private final static Singleton3 instance = new Singleton3();
}
public static Singleton3 getInstance(){
return InstanceHolder.instance;
}
}
- 借用枚举
public class Singleton4 {
private Singleton4(){
}
private enum Singleton {
INSTANCE;
private final Singleton4 instance;
Singleton() {
instance = new Singleton4();
}
public Singleton4 getInstance() {
return instance;
}
}
public static Singleton4 getInstance() {
return Singleton.INSTANCE.getInstance();
}
}
网友评论