rainyzz's blog

如何实现一个正确的单例模式

一般面试中能现场写的设计模式也只有单例模式了,一个正确的单例模式主要需要考虑:

  • 代码正确
  • 线程安全
  • 最好是懒加载

接下来是三种符合该种条件单例模式的实现

##双重锁检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Singleton{
private Singleton(){}
private volatile static Singleton instance = null;
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}

这种是最复杂的,在instance为null时声明新对象,因为不需要每次判断instance是否为null时都调用synchronized,所以将synchronized写在if语句内。然后再次判断是否为null,因为多线程的情况有可能在第一次判定为null后又有了别的操作,导致instance不为null。

此外,还要注意使用volatile关键字,禁止指令重排序导致的多次new Singleton()操作。

##内部类

1
2
3
4
5
6
7
8
9
10
public class Singleton{
private Singleton(){}
private static class SingletonHolder{
static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}

使用静态内部类也可以达到懒加载,即访问instance时才初始化SingletonHolder类。同时静态变量又由系统确保了线程安全。也是算一种比较便捷的方式。

##枚举类型
枚举类型写单例是最方便的,也是《Effective Java》上推荐的一种方式,Java中的枚举类型已经和C语言中的完全不一样了,Java中的枚举类型和正常的class基本是一样的,里面可以有成员变量,有方法,也可以继承接口等。

1
2
3
4
public enum Singleton{
ONE;
public void method(){}
}

获取单例的对象使用Singleton.ONE即可。