mov 0xc(%r10),%r8d ; Load
inc %r8d ; Increment
mov %r8d,0xc(%r10) ; Store
lock addl $0x0,(%rsp) ; StoreLoad Barrier
lock 前缀指令实际上相当于一个内存屏障(也叫内存栅栏),内存屏障会提供 3 个功能:
它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成(满足禁止重排序)
它会强制将对缓存的修改操作立即写入主存(满足可见性)
如果是写操作,它会导致其他 CPU 中对应的缓存行无效(满足可见性)
volatile 变量规则是 happens-before(先行发生原则)中的一种:对一个变量的写操作先行发生于后面对这个变量的读操作。(该特性可以很好解释 DCL 双重检查锁单例模式为什么使用 volatile 关键字来修饰能保证并发安全性)
变量声明为 volatile 类型时,编译器与运行时都会注意到这个变量是共享的,不会将该变量上的操作与其他内存操作一起重排序。volatile 变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取 volatile 类型的变量时总会返回最新写入的值。
在访问 volatile 变量时不会执行加锁操作,也就不会使执行线程阻塞,因此 volatile 变量是比 sychronized 关键字更轻量级的同步机制。
加锁机制既可以确保可见性和原子性,而 volatile 变量只能确保可见性。