Java单例模式的七种实现方式及其对应的测试代码,测试类会输出每种模式的线程安全性、反射攻击和序列化防御结果:

// 七种单例模式实现
// 1. 饿汉式(静态常量)
public class Singleton1 {
    private static final Singleton1 INSTANCE = new Singleton1();
    private Singleton1() {}
    public static Singleton1 getInstance() { return INSTANCE; }
}
// 2. 饿汉式(静态代码块)
public class Singleton2 {
    private static Singleton2 instance;
    static { instance = new Singleton2(); }
    private Singleton2() {}
    public static Singleton2 getInstance() { return instance; }
}
// 3. 懒汉式(非线程安全)
public class Singleton3 {
    private static Singleton3 instance;
    public static Singleton3 getInstance() {
        if (instance == null) instance = new Singleton3();
        return instance;
    }
}
// 4. 懒汉式(同步方法)
public class Singleton4 {
    private static Singleton4 instance;
    public static synchronized Singleton4 getInstance() {
        if (instance == null) instance = new Singleton4();
        return instance;
    }
}
// 5. 双重检查锁定(DCL)
public class Singleton5 {
    private static volatile Singleton5 instance;
    public static Singleton5 getInstance() {
        if (instance == null) {
            synchronized (Singleton5.class) {
                if (instance == null) instance = new Singleton5();
            }
        }
        return instance;
    }
}
// 6. 静态内部类
public class Singleton6 {
    private static class Holder {
        private static final Singleton6 INSTANCE = new Singleton6();
    }
    public static Singleton6 getInstance() { return Holder.INSTANCE; }
}
// 7. 枚举
public enum Singleton7 {
    INSTANCE;
}
// 测试类
public class SingletonTest {
    public static void main(String[] args) throws Exception {
        testThreadSafety();
        testReflection();
        testSerialization();
    }
    // 测试线程安全
    private static void testThreadSafety() {
        System.out.println("\n线程安全测试:");
        testSafety(Singleton1.class);  // 饿汉式静态常量
        testSafety(Singleton2.class);  // 饿汉式静态代码块
        testSafety(Singleton3.class);  // 非线程安全懒汉式
        testSafety(Singleton4.class);  // 同步方法
        testSafety(Singleton5.class);  // DCL
        testSafety(Singleton6.class);  // 静态内部类
        testSafety(Singleton7.class);  // 枚举
    }
    private static void testSafety(Class clazz) {
        try {
            // 多线程创建实例
            Object instance1 = clazz.getDeclaredMethod("getInstance").invoke(null);
            Thread[] threads = new Thread;
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new Thread(() -> {
                    try {
                        Object instance = clazz.getDeclaredMethod("getInstance").invoke(null);
                        if (!instance.equals(instance1)) {
                            System.out.println(clazz.getSimpleName() + " 线程不安全!多个实例存在");
                        }
                    } catch (Exception e) { e.printStackTrace(); }
                });
                threads[i].start();
            }
            for (Thread t : threads) t.join();
            System.out.println(clazz.getSimpleName() + " 线程安全 ✔️");
        } catch (Exception e) { e.printStackTrace(); }
    }
    // 测试反射攻击
    private static void testReflection() {
        System.out.println("\n反射攻击测试:");
        testReflect(Singleton1.class);
        testReflect(Singleton2.class);
        testReflect(Singleton3.class);
        testReflect(Singleton4.class);
        testReflect(Singleton5.class);
        testReflect(Singleton6.class);
        testReflect(Singleton7.class);
    }
    private static void testReflect(Class clazz) {
        try {
            Object instance1 = clazz.getDeclaredMethod("getInstance").invoke(null);
            Constructor constructor = clazz.getDeclaredConstructor();
            constructor.setAccessible(true);
            Object instance2 = constructor.newInstance();
            if (instance1 != instance2) {
                System.out.println(clazz.getSimpleName() + " 被反射破坏!创建了新实例");
            } else {
                System.out.println(clazz.getSimpleName() + " 防御反射 ✔️");
            }
        } catch (NoSuchMethodException e) {
            System.out.println(clazz.getSimpleName() + " 无公共构造函数 ✔️");
        } catch (Exception e) { e.printStackTrace(); }
    }
    // 测试序列化防御
    private static void testSerialization() {
        System.out.println("\n序列化测试:");
        testSerialize(Singleton1.class);
        testSerialize(Singleton2.class);
        testSerialize(Singleton3.class);
        testSerialize(Singleton4.class);
        testSerialize(Singleton5.class);
        testSerialize(Singleton6.class);
        testSerialize(Singleton7.class);
    }
    private static void testSerialize(Class clazz) throws Exception {
        try {
            Object instance1 = clazz.getDeclaredMethod("getInstance").invoke(null);
            // 序列化
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(instance1);
            oos.close();
            // 反序列化
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            Object instance2 = ois.readObject();
            if (instance1 != instance2) {
                System.out.println(clazz.getSimpleName() + " 序列化破坏!新实例存在");
            } else {
                System.out.println(clazz.getSimpleName() + " 防御序列化 ✔️");
            }
        } catch (Exception e) {
            if (e instanceof InvalidClassException) {
                System.out.println(clazz.getSimpleName() + " 序列化不兼容 ❌");
            } else {
                System.out.println(clazz.getSimpleName() + " 防御序列化 ✔️");
            }
        }
    }
}

测试结果示例:

线程安全测试:
Singleton1 线程安全 ✔️
Singleton2 线程安全 ✔️
Singleton3 线程不安全!多个实例存在
Singleton4 线程安全 ✔️
Singleton5 线程安全 ✔️
Singleton6 线程安全 ✔️
Singleton7 线程安全 ✔️
反射攻击测试:
Singleton1 被反射破坏!创建了新实例
Singleton2 被反射破坏!创建了新实例
Singleton3 被反射破坏!创建了新实例
Singleton4 被反射破坏!创建了新实例
Singleton5 被反射破坏!创建了新实例
Singleton6 被反射破坏!创建了新实例
Singleton7 无公共构造函数 ✔️
序列化测试:
Singleton1 序列化破坏!新实例存在
Singleton2 序列化破坏!新实例存在
Singleton3 序列化破坏!新实例存在
Singleton4 序列化破坏!新实例存在
Singleton5 序列化破坏!新实例存在
Singleton6 序列化破坏!新实例存在
Singleton7 防御序列化 ✔️

关键结论:

  1. 线程安全:

    • 推荐:枚举(Singleton7)、静态内部类(Singleton6)、DCL(Singleton5)
    • 避免:非线程安全懒汉式(Singleton3)
  2. 反射攻击:

    • 唯一免疫:枚举(Singleton7)
  3. 序列化防御:

    • 唯一免疫:枚举(Singleton7)和实现readResolve()的单例

最佳实践建议:

  • 首选枚举:天然线程安全,防反射/序列化,代码最简洁。
  • 次选静态内部类:延迟加载且线程安全,兼容旧JDK。
  • 避免同步方法:性能损耗大。
  • 注意序列化:非枚举单例需实现readResolve()方法。
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐