为何static final单例实例的getter方法需添加synchronized修饰符?
为何static final单例的getter方法需要添加synchronized修饰符?
针对你提出的问题,结合Spotbugs的SING_SINGLETON_GETTER_NOT_SYNCHRONIZED检查和SEI CERT MSC07-J规则,核心原因可以拆成两点:
1. 当前代码的synchronized其实是冗余的,但JVM已保证线程安全
你用到的饿汉式单例(static final字段直接初始化),本身已经具备线程安全性:
- JVM在类加载的
<clinit>初始化阶段,会自动保证static字段初始化的线程安全——多个线程同时触发类加载时,只会有一个线程执行初始化逻辑,其他线程会阻塞等待。 - static final字段初始化完成后,JVM会禁止指令重排序,确保
getInstance()返回的INSTANCE是完全初始化的实例,不存在半初始化状态的问题。
所以从当前代码的功能角度看,synchronized确实是多余的。
2. 规则要求加synchronized是出于防御性编程的考虑
SEI CERT MSC07-J规则和Spotbugs的检查,本质是从代码长期维护性出发的强制规范:
- 避免重构失误:如果后续有人修改单例实现(比如改成懒加载的延迟初始化),忘记给
getInstance()加synchronized,就会出现多线程创建多个实例的线程安全问题。提前加上synchronized,可以避免这类重构时的疏漏。 - 统一规范:规则覆盖所有单例实现场景,不管是饿汉还是懒汉,统一要求同步getter方法,减少开发者需要判断的场景,降低出错概率。
简单来说,这个要求不是针对当前代码的必要性,而是为了代码未来的可维护性,提前做好防御。
内容的提问来源于stack exchange,提问作者Volkan Yazıcı
相关产品推荐
相关产品推荐

