Java单例类构造方法中的synchronized块为何未实现线程同步?
问题原因解答
这个现象的核心问题出在构造方法调用路径和单例逻辑的赋值时机不匹配,具体原因如下:
- 你全程是通过反射直接调用
TestClass的私有构造方法创建实例,没有调用过getInstance()方法。而TestClass里的静态变量instance只有在getInstance()方法执行时才会被赋值,整个测试过程中instance一直是初始的null值。 - 构造方法内的校验逻辑只有判断
instance != null时才抛出异常,但你并没有在构造方法内把当前创建的实例(this)赋值给静态变量instance:第一个线程拿到类锁进入同步块,判断instance是null就正常完成构造,释放锁后第二个线程拿到锁进入同步块,此时instance还是null,自然不会触发异常,成功创建第二个实例。 - 你没有重写
TestClass的equals方法,Java中默认的equals逻辑和==完全一致,两个不同的堆实例对比自然输出两个false。
修复验证方案
如果要让构造方法内的防反射破坏逻辑生效,只需要在构造方法的同步块中补充实例赋值逻辑即可:
private TestClass() { synchronized (TestClass.class) { for (int i = 0; i < 100000; i++) ; if (instance != null) { throw new RuntimeException("Operation not allowed. Use getInstance method."); } // 新增赋值逻辑,把当前创建的实例绑定到静态变量 instance = this; } }
修改后再次运行测试代码,第二个线程调用构造方法时就会抛出预期的运行时异常。
内容的提问来源于stack exchange,提问作者Abhishek Verma
相关产品推荐
相关产品推荐

