Loading...
avatar

单例模式

定义

一个类只有一个实例,该实例必须自行创建,并且向整个系统提供这个实例

实现考虑因素

  • 唯一性
    • 是否防克隆
    • 是否防反射
    • 是否防序列化
  • 性能
    • 是否需要懒加载
    • 是否防指令重排(双重锁方式问题)

三种实现方式

实现 懒加载 线程安全 防克隆 防反射 防序列化
双重锁
静态内部类
枚举

双重锁方式(添加了防御功能)

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
28
29
30
31
32
public class Singleton implements Serializable, Cloneable {

private static volatile Singleton sSingleton; // volatile防止指令重排
private static boolean sFlag = true;
private Singleton() {
if(sFlag){ // 防反射
sFlag = false;
}else{
throw new RuntimeException("对象已经存在");
}
}

public static Singleton getSingleton() {
if (sSingleton == null) {
synchronized (Singleton.class) {
if (sSingleton == null) {
sSingleton = new Singleton();
}
}
}
return sSingleton;
}

private Object readResolve() {
return getSingleton(); // 防序列化
}

@Override
protected Object clone() throws CloneNotSupportedException {
return getSingleton(); // 防克隆
}
}

静态内部类方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Instance {
private Instance() {
}

private static class Holder {
// 类加载机制保证懒加载,static&final确保线程安全
private static final Instance INSTANCE = new Instance();
}

public static Instance getInstance() {
return Holder.INSTANCE;
}

}

枚举类方式

1
2
3
4
5
public enum Single {
SINGLE;
public void whateverMethod(){
}
}

基本等价于(除enum的防反射、序列化、克隆等属性)

1
2
3
public final class Single{
public static final Single SINGLE = new Single();
}

测试代码

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public static void main(String args[]) {

try {
Singleton singleton = Singleton.getSingleton();
testCloneSingleton(singleton);
testReflectSingleton(singleton);
testSerializableSingleton(singleton);

} catch (Exception e) {
e.printStackTrace();
}
}

private static void testCloneSingleton(Singleton singleton) throws CloneNotSupportedException {

boolean equals = singleton.equals(Singleton.getSingleton().clone());

System.out.print(equals);
}

private static void testReflectSingleton(Singleton singleton) throws Exception {
Constructor constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
constructor.newInstance();

boolean equals = singleton.equals(constructor.newInstance(););

System.out.print(equals);

}

private static void testSerializableSingleton(Singleton singleton) throws Exception {
String tempFile = "tempFile";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(tempFile));
oos.writeObject(getSingleton());
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(new File(tempFile)));

boolean equals = singleton.equals(objectInputStream.readObject());

System.out.print(equals);

}
Author: Afree
Link: https://afree8909.github.io/blog/2018/02/03/%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.

Comment