定义
一个类只有一个实例,该实例必须自行创建,并且向整个系统提供这个实例
实现考虑因素
- 唯一性
- 是否防克隆
- 是否防反射
- 是否防序列化
- 性能
- 是否需要懒加载
- 是否防指令重排(双重锁方式问题)
三种实现方式
实现 | 懒加载 | 线程安全 | 防克隆 | 防反射 | 防序列化 |
---|---|---|---|---|---|
双重锁 | 是 | 是 | 否 | 否 | 否 |
静态内部类 | 是 | 是 | 否 | 否 | 否 |
枚举 | 否 | 是 | 是 | 是 | 是 |
双重锁方式(添加了防御功能)
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(); // 防克隆
}
}
静态内部类方式
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;
}
}
枚举类方式
public enum Single {
SINGLE;
public void whateverMethod(){
}
}
基本等价于(除enum的防反射、序列化、克隆等属性)
public final class Single{
public static final Single SINGLE = new Single();
}
测试代码
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);
}