定义
一个类只有一个实例,该实例必须自行创建,并且向整个系统提供这个实例
实现考虑因素
三种实现方式
| 实现 |
懒加载 |
线程安全 |
防克隆 |
防反射 |
防序列化 |
| 双重锁 |
是 |
是 |
否 |
否 |
否 |
| 静态内部类 |
是 |
是 |
否 |
否 |
否 |
| 枚举 |
否 |
是 |
是 |
是 |
是 |
双重锁方式(添加了防御功能)
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);
}
|