0. UML结构图
1. 四种安全的单例示例
1.1 单例-饿汉式
public class SingletonDemo01 {
private static SingletonDemo01 instance = new SingletonDemo01();
private SingletonDemo01() {
}
public static SingletonDemo01 getInstance() {
return instance;
}
}
1.2 单例-懒汉式(双重校验锁)
public class SingletonDemo02 {
private static volatile SingletonDemo02 instance;
private SingletonDemo02() {
}
public static SingletonDemo02 getInstance() {
if (instance == null) {
synchronized (SingletonDemo02.class) {
if (instance == null) {
instance = new SingletonDemo02();
}
}
}
return instance;
}
}
1.3 单例-静态内部类(推荐)
public class SingletonDemo03 {
private SingletonDemo03() {
}
public static SingletonDemo03 getInstance() {
return InnerClass.instance;
}
private static class InnerClass {
private static final SingletonDemo03 instance = new SingletonDemo03();
}
}
1.4 单例-枚举(推荐)
public enum SingletonDemo04 {
INSTANCE;
}
1.5 4种单例的测试
public class SingletonTest {
public static void main(String[] args) {
SingletonDemo01 instance1 = SingletonDemo01.getInstance();
SingletonDemo01 instance2 = SingletonDemo01.getInstance();
System.out.println(instance1 == instance2);
SingletonDemo02 instance3 = SingletonDemo02.getInstance();
SingletonDemo02 instance4 = SingletonDemo02.getInstance();
System.out.println(instance3 == instance4);
SingletonDemo03 instance5 = SingletonDemo03.getInstance();
SingletonDemo03 instance6 = SingletonDemo03.getInstance();
System.out.println(instance5 == instance6);
SingletonDemo04 instance7 = SingletonDemo04.INSTANCE;
SingletonDemo04 instance8 = SingletonDemo04.INSTANCE;
System.out.println(instance7 == instance8);
}
}
2. 单例防破解
2.1 防止反射、反序列化的单例Code示例
import java.io.ObjectStreamException;
import java.io.Serializable;
public class SingletonDemo05 implements Serializable {
private static volatile SingletonDemo05 instance;
private SingletonDemo05() {
if (instance != null) {
throw new RuntimeException("只能实例化一个对象");
}
}
public static SingletonDemo05 getInstance() {
if (instance == null) {
synchronized (SingletonDemo05.class) {
if (instance == null) {
instance = new SingletonDemo05();
}
}
}
return instance;
}
private Object readResolve() throws ObjectStreamException {
return instance;
}
}
2.2 带可序列化接口的单例Code示例(附加的测试用类)
public class SingletonDemo02Serializable implements Serializable {
private static SingletonDemo02Serializable instance;
private SingletonDemo02Serializable() {
}
public static SingletonDemo02Serializable getInstance() {
if (instance == null) {
synchronized (SingletonDemo02Serializable.class) {
if (instance == null) {
instance = new SingletonDemo02Serializable();
}
}
}
return instance;
}
}
2.3 单例防破解测试
import java.io.*;
import java.lang.reflect.Constructor;
public class AntiCrashSingletonTest {
public static void main(String[] args) {
reflect();
unserializable();
}
public static void reflect() {
try {
SingletonDemo02 o1 = SingletonDemo02.getInstance();
Class<SingletonDemo02> clazz = (Class<SingletonDemo02>) Class.forName("com.skey.designpattern.singleton.SingletonDemo02");
Constructor<SingletonDemo02> constructor = clazz.getDeclaredConstructor(null);
constructor.setAccessible(true);
SingletonDemo02 o2 = constructor.newInstance();
System.out.println(o1 == o2);
} catch (Exception e) {
e.printStackTrace();
}
try {
SingletonDemo05 o3 = SingletonDemo05.getInstance();
Class<SingletonDemo05> clazz05 = (Class<SingletonDemo05>) Class.forName("com.skey.designpattern.singleton.SingletonDemo05");
Constructor<SingletonDemo05> constructor05 = clazz05.getDeclaredConstructor(null);
constructor05.setAccessible(true);
SingletonDemo05 o4 = constructor05.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void unserializable() {
String path1 = "./test1.txt";
SingletonDemo02Serializable o1 = SingletonDemo02Serializable.getInstance();
try (FileOutputStream fos = new FileOutputStream(path1);
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(o1);
} catch (IOException e) {
e.printStackTrace();
}
try(FileInputStream fis = new FileInputStream(path1);
ObjectInputStream ois = new ObjectInputStream(fis)) {
SingletonDemo02Serializable o2 = (SingletonDemo02Serializable) ois.readObject();
System.out.println(o2 == o1);
} catch (Exception e) {
e.printStackTrace();
}
String path2 = "./test2.txt";
SingletonDemo05 o3 = SingletonDemo05.getInstance();
try (FileOutputStream fos = new FileOutputStream(path2);
ObjectOutputStream oos = new ObjectOutputStream(fos)) {
oos.writeObject(o3);
} catch (IOException e) {
e.printStackTrace();
}
try(FileInputStream fis = new FileInputStream(path2);
ObjectInputStream ois = new ObjectInputStream(fis)) {
SingletonDemo05 o4 = (SingletonDemo05) ois.readObject();
System.out.println(o4 == o3);
} catch (Exception e) {
e.printStackTrace();
}
}
}