Java 后端面试题库 / 全部题解免费阅读理解原理,有条理地回答

怎样实现一个可靠的 Java 单例?

先说出你的答案

定义边界、关键机制、一个反例;P8题再补容量、失败与验证。

查看完整题解

参考回答

直接回答

若类型需求合适,枚举单例是简洁选择,语言及原生序列化机制会维护相应的枚举实例语义。普通类也可采用静态持有者实现延迟初始化。无论哪一种,“单例”都需限定到相应运行时类和类加载器,不能直接推导成多进程、多服务器只有一个对象。

讲清原理

安全创建与安全使用要分开:类初始化机制可以保证实例创建与发布的相应安全性,但单例内部可变字段的并发更新仍要自己设计。普通类的 private 构造器也不能自动解决所有反射、克隆和序列化路径。

例子与易错点

enum Registry { INSTANCE }
System.out.println(Registry.INSTANCE == Registry.valueOf("INSTANCE")); // true

不适合使用枚举时,下面是普通类的静态持有者写法;该代码块声明为外部类的静态成员:

static final class Singleton {
    private Singleton() {}
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
    static Singleton instance() { return Holder.INSTANCE; }
}

首次调用 instance() 并读取 Holder.INSTANCE 时,会触发 Holder 的初始化,不必自己拼装双重检查锁。若添加原生序列化或开放反射使用场景,需要重新审视普通类的唯一性边界。跨进程协调则是另一类系统问题。

相关题:第 33 题、第 43 题、第 44 题、第 51 题。

这道题,你掌握得怎么样?

掌握程度由你主动标记,阅读和收藏不会自动改变状态。