具体为什么会出现这些问题就不多说了……
指令重排( Instruction reordering)
多线程访问共享变量的顺序可能不是你代码写的顺序。
例子 https://stackoverflow.com/questions/52648800/how-to-demonstrate-java-instruction-reordering-problems
可见性问题(Visibility)
多线程修改一个变量,另一个线程读取的可能是修改前的值
学 Java 的应该都知道的一个例子,单例模式中的双重检查锁(Double checked locking)。
还有一个例子,在上面 stackoverflow 网站中给出的例子当中代码执行出乎意料,其实也有可能是内存可见性的问题。
在评论中也有人指出了这个问题。不过在 X86 中不存在可见性问题。
虚假唤醒(Spurious wakeup)
线程会莫名其妙的被唤醒
例子 /t/902578 见回复简化的例子 /t/902578#r_12468983
伪共享(False sharing)
多线程访问同一个缓存行,导致缓存频繁失效。
例子 https://jenkov.com/tutorials/java-concurrency/false-sharing.html
去掉 @jdk.internal.vm.annotation.Contended 和不去掉的运行时间差别非常大。40s -> 6s
原子性
多线程读取修改同一个变量,修改会被相互覆盖。
Int a = 0
Thread 1 :
for 0 to 100:
a=a+1
Thread 2 :
for 0 to 100:
a=a+1
最后的结果不一定是 200