之所以可行,是因为Java的内存模型较弱。它不保证读写顺序。
可以通过以下代表两个线程的两个代码片段来重现此特定问题。
线程1:
someStaticVariable = new Holder(42);
线程2:
someStaticVariable.assertSanity(); // can throw
表面上看来这不可能发生。为了理解为什么会发生这种情况,您必须超越Java语法,并降低到更低的水平。如果您看一下线程1的代码,它实际上可以分解为一系列的内存写和分配:
- 分配内存到指针1
- 在偏移量0处将42写入指针1
- 将指针1写入someStaticVariable
由于Java的内存模型较弱,因此从线程2的角度来看,代码完全有可能按以下顺序实际执行:
- 分配内存到指针1
- 将指针1写入someStaticVariable
- 在偏移量0处将42写入指针1
害怕?是的,但是有可能发生。
但是,这意味着线程2现在可以
assertSanity在
n获得值42
之前调用它。在操作#3完成之前,在操作#3完成之后,在操作之后一次都
n可以读取该值两次
assertSanity,因此可以看到两个不同的值并引发异常。
。
编辑
据乔恩斯基的
AssertionErrormigh仍然发生的Java8除非该场决赛。



