# 单例模式
# 一、懒汉式-非线程安全
public class Singleton {
private static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (null == instance) {
instance = new Singleton();
}
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 二、饿汉式--性能低
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 三、懒汉双检锁-线程安全
public class Singleton {
private volatile static Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (null == instance) {
synchronized (Singleton.class) {
if (null == instance) {
instance = new Singleton();
}
}
}
return instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1. 为什么需要双重检查
假设两个线程A,B都进入这个方法,判断instance为空,开始争抢Singleton.class锁。当A获取到锁,进行实例的创建,然后释放锁。这时候B等待完毕苏醒也拿到了锁,往下执行就会重复创建对象。
public static Singleton getInstance() { if (null == instance) { synchronized (Singleton.class) { instance = new Singleton(); } } return instance; }
1
2
3
4
5
6
7
8
**2. volatile 原因:**防止指令重排序
通过javap -v Demo.class反编译可以看到:
instance = new Singleton()
可以拆分为多步:比如
堆上开辟内存 new
初始化对象 dup + invokespecial
指向分配的内存地址 astore_1
假设 A 线程 执行了1和3,还没执行2,B线程判断 NULL,B 线程就会返回还没初始化的 instance 了,volatile 可以避免指令重排序
# 四、静态内部类-线程安全
public class Singleton {
private Singleton() {
}
private static class InnerClass {
private static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return InnerClass.instance;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
通过类加载保证线程安全 通过类的加载是线程安全的保证实例的唯一性, 当调用getInstance时触发Singleton类加载,加载过程中会加载InnerClass内部类,加载InnerClass的同时会创建Singleton实例,同时InnerClass是private的,所以保证了唯一性
# 五、枚举
public enum Singleton {
INSTANCE;
}
1
2
3
2
3
# 六、JDK中的单例
public class Runtime {
private static final Runtime currentRuntime = new Runtime();
private Runtime() {}
public static Runtime getRuntime() {
return currentRuntime;
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9