同一个JVM中保证实例的唯一性
饿汉式
1
2
3
4
5
6
7
8
9
10
11
12
13
| public final class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){
// 私有化构造函数
}
public static Singleton getInstance(){
return instance;
}
}
|
- 优点:JVM在类加载初始化阶段
<clinit>()
会保证INSTANCE 的唯一性。
- 缺点:无法进行懒加载,可能很长时间才被使用。
懒汉式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public final class Singleton {
private static Singleton instance;
private Singleton() {
// 私有化构造函数
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
|
- 优点:可以懒加载。
- 缺点:多线程情况下不保证
INSTANCE
的唯一性。
懒汉式+同步方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public final class Singleton {
private static Singleton instance;
private Singleton() {
// 私有化构造函数
}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
|
- 优点:既可以保证单实例又可以实现懒加载。
- 缺点:synchronized加在方法上多线程的情况下效率低。
Double Check Lock
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| public final class Singleton {
private static Singleton instance;
private Singleton() {
// 私有化构造函数
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
|
- 优点:解决synchronized多线程情况下效率低的问题。
- 缺点:多线程在获取实例的时候有可能得到的是一个未初始化完成的对象。
Volatile+DCL
创建一个对象分为三部:
- 分配内存
- 初始化对象
- 把对应内存空间地址赋给相关引用
问题:由于JVM的重排序以及Happens-Before规则,以上三步并不一定按顺序发生,有可能2和3先后顺序发生变化就会出现获得一个还未初始化完成的对象。
解决:加上volatile
关键字禁止指令重排序。
volatile 保证可见性和禁止指令重排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| public final class Singleton {
private static volatile Singleton instance;
private Singleton() {
// 私有化构造函数
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
|
内部类
由JVM类加载初始化阶段(<clinit>()
)保证实例的唯一性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| public final class Singleton {
private static volatile Singleton instance;
private Singleton() {
// 私有化构造函数
}
private static class Holder{
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return Holder.instance;
}
}
|
- 既保证多线程的情况下线程安全又实现懒加载以及写法便捷。
枚举方式
枚举的本质是一个final类。
1
2
3
4
5
6
7
8
9
| public enum Singleton {
INSTANCE;
public static Singleton getInstance(){
return INSTANCE;
}
}
|
- 优点:由JVM保证实例的唯一性,也是《Effective Java》作者推荐的方式。
- 缺点:无法懒加载。
枚举改进
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
private Singleton() {
// 私有化构造函数
}
private enum EnumHolder {
INSTANCE;
private Singleton SINGLETON;
EnumHolder() {
SINGLETON = new Singleton();
}
private Singleton getInstance() {
return SINGLETON;
}
}
public static Singleton getInstance() {
return EnumHolder.INSTANCE.getInstance();
}
}
|