单例模式是一种常见的设计模式,它的写法也有好几种,这里主要介绍三种:懒汉式、饿汉式、枚举类实现。

懒汉式单例

基础饿汉式单例

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton {

private static Singleton singleton;

private Singleton (){}

public static Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}

  Singlon将构造函数设置为私有,使得外部能够获取的唯一Singlon实例只能通过getInstance方法创建。


  但是以上饿汉式单例并没有考虑多线程的情况,在多线程时任会产生多个实例。可以添加synchornized关键字加以优化。

方法同步

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Singleton {

private static Singleton singleton;

private Singleton (){}

public synchronized static Singleton getInstance(){
if (singleton == null) {
singleton = new Singleton();
}

return singleton;
}

}

  加入静态方法同步可以实现多线程的情况下只有一个实例被创建。但是同时也会有些问题:只有第一次创建实例时才需要添加类锁,因此之后的方法调用的同步都是一种累赘。可以利用双重检查锁加以改进。

双重检查锁定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Singleton {

//volatile 可以禁止指令重排序
private volatile static Singleton singleton;

private Singleton (){}

public static Singleton getInstance(){
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
// 这句语句指令重排序会产生问题?
singleton = new Singleton();
}
}
}
return singleton;
}
}

饿汉式单例

1
2
3
4
5
6
7
8
public class Singleton {
//在类初始化时,已经自行实例化
private static Singleton singleton = new Singleton();
private Singleton (){}
public static Singleton getInstance(){
return singleton;
}
}

  饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。但由于并不一定是在创建后立即使用甚至可能根本不使用该对象,因此此方式会造成一定的内存浪费。

枚举类单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Singleton {

private Singleton(){};

public static Singleton getInstance() {
return SomeThing.INSTANCE.getInstance();
}

private enum SomeThing {
INSTANCE;
private Singleton instance;
SomeThing() {
instance = new Singleton();
}
public Singleton getInstance() {
return instance;
}
}
}

从Java 1.5版本起,单元素枚举实现单例模式成为最佳的方法