synchronized锁升级和volatile关键字随笔

  • 对volatile关键字的理解

volatile是Java语言的一个关键字,它可以解决线程可见性的问题。

原理就是volatile关键字会开启cpu的MESI缓存一致性协议,即在主内存和工作内存之间开启一条总线。
这条总线会记录所有线程各自使用的数据。

当检测到有数据将要执行write/store命令写入主内存的时候,别的线程会通过总线嗅探机制知道这件事(该数据发生修改)。

此时cpu将会立即把这个数据写入主内存,然后其他线程将会把自己工作内存中相对应的数据副本删除,之后再从主内存获取新的副本。

使用volatile关键字之后,汇编指令集中就会多出一条lock指令,该指令执行了两个过程:
① 把该线程中的缓存数据立即写回主内存
② 这个写操作就会触发MESI协议的总线嗅探机制,通知别的线程数据修改

当cpu中有多个线程同时进行时,出于优化的原因,cpu可能是乱序执行字节码的。使用volatile关键字还可以禁止指令重排,防止出现对象的半初始化。

  • synchronized的锁升级过程

在JVM启动时间没超过4s时,此时没有启动偏向锁。当有线程执行同步代码块时,就会发生锁升级,升级为轻量级锁(自旋锁,CAS,性能快但cpu占用率高);

但是当有其他线程经过3-5微秒的等待仍拿不到锁对象(发生锁竞争),锁就会再次进行升级,升级为重量级锁(使用了cpu内核操作,拿不到锁的线程会进入等待状态,不消耗cpu资源,性能慢但吞吐量大)。

当JVM启动时间超过4s时,偏向锁可以启动了,当有线程执行同步代码块时,就会发生锁升级,升级为偏向锁(实质是一个if判断,判断当前是否只有该线程在使用锁);

但是偏向锁不会自己释放,只有当第二个线程来使用锁,偏向锁才会释放并升级成轻量级锁;

然后当有其他线程经过3-5微秒的等待仍拿不到锁对象,锁就会再次进行升级,升级为重量级锁(之后的过程和上面一致)。
synchronized锁升级和volatile关键字随笔
锁的升级不可逆,锁是按照 无锁 --> (偏向锁) --> 轻量级锁 --> 重量级锁 这个步骤来升级的。例如当锁升级为轻量级锁后,就不可能降级为偏向锁。