0%

Java单例模式常见实现方式

单例模式:确保一个类在任何情况下只有一个实例,并提供一个全局访问点,隐藏其所有构造方法

饿汉式

1
2
3
4
5
6
7
8
9
// 声明时就初始化实例,缺点是浪费空间
public class HungrySingleton {
private static final HungrySingleton HUNGRY_SINGLETON = new HungrySingleton();
private HungrySingleton() {}

public static HungrySingleton getInstance() {
return HUNGRY_SINGLETON;
}
}

懒加载

普通方式

1
2
3
4
5
6
7
8
9
10
11
12
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}

// 添加synchronized保证线程安全
public synchronized static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}

Double-Check

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
// 要考虑线程安全,性能会受影响
public class LazyDoubleCheckSingleton {
// 添加volatile 解決指令重排序的問題

// CPU执行时会转换成JVM指令执行
// 1. 为对象分配内存
// 2. 初始化对象
// 3. 关联对象与内存地址, 为对象赋值
// 4. 用户初次访问
// 指令执行时,顺序可能会颠倒 (指令重排序)

private static volatile LazyDoubleCheckSingleton instance;
private LazyDoubleCheckSingleton() {}

// Double Check
public static LazyDoubleCheckSingleton getInstance() {
if (instance == null) {
synchronized (LazyDoubleCheckSingleton.class) {
if (instance == null) {
instance = new LazyDoubleCheckSingleton();
}
}
}
return instance;
}
}

内部类实现懒加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 不占空间,性能比较好
public class LazyInnerClassSingleton {
// 私有构造方法中添加判断 避免反射破坏单例的创建
private LazyInnerClassSingleton() {
if (LazyHolder.instance != null) {
throw new RuntimeException("不允许构建多个实例");
}
}

public synchronized static LazyInnerClassSingleton getInstance() {
return LazyHolder.instance;
}

// instance 的实例化逻辑要等到 getInstance方法调用时才会执行
// 静态内部类在外部类加载时, 不会同时加载,只有当内部类的某个成员变量,方法,或构造函数被调用时,才会加载内部类
private static class LazyHolder {
private static final LazyInnerClassSingleton instance = new LazyInnerClassSingleton();
}
}

容器式单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 利用map实现单例模式
public class ContainerSingleton {
private static final ConcurrentHashMap<String, Object> container = new ConcurrentHashMap<>();

private ContainerSingleton() {

}

public static Object getBean(String className) {
synchronized (container) {
if (!container.containsKey(className)) {
Object object = null;
try {
object = Class.forName(className);
container.put(className, object);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return container.get(className);
}
}
}

枚举实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public enum  EnumSingleton {
// 只有一个实例
INSTANCE;

private Object data;
// 提供全局唯一方法
public static EnumSingleton getInstance() {
return INSTANCE;
}

public Object getData() {
return data;
}

public void setData(Object data) {
this.data = data;
}
}

ThreadLocal实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 保证线程内是单例的
public class ThreadLocalSingleton {
private static final ThreadLocal<ThreadLocalSingleton> threadLocalInstance =
new ThreadLocal<ThreadLocalSingleton>(){
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};

private ThreadLocalSingleton(){}

public static ThreadLocalSingleton getInstance(){
return threadLocalInstance.get();
}
}

Serializable实现单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class SerializableSingleton implements Serializable {
private static final SerializableSingleton INSTANCE = new SerializableSingleton();
private SerializableSingleton() {}

public static SerializableSingleton getInstance() {
return INSTANCE;
}

// ObjectOutputStream 在 反序列化对象时,在创建对象实例后,会检查是否有readResolve方法,
// 如果有会运用反射调用 readResolve方法覆盖 对象实例
private Object readResolve() {
return INSTANCE;
}
}

破坏单例的方法

  1. 通过反射获取单例的构造方法,创建实例
  2. 通过将单例序列化再反序列化后,也会破坏单例 (可以在单例内添加readResolve方法解决)