Synchronized 锁升级机制

116 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情


偏向锁

同一个线程,在不存在竞争的情况下,只需要判断当前锁信息中记录的线程ID是否为自己线程ID

轻量级锁

也称为自旋锁,通过CAS自旋机制实现。

重量级锁

通过 moniterenter、moniterexit 两个JVM指令,获取对象监视器 monitor 对象。

在执行monitorenter时,会尝试获取对象的锁,如果锁的计数器为 0 则表示锁可以被获取,获取后将锁计数器设为 1 也就是加 1。.对象锁的的拥有者线程才可以执行 monitorexit 指令来释放锁。在执行 monitorexit 指令后,将锁计数器设为 0,表明锁被释放,其他线程可以尝试获取锁。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止。

线程的阻塞与唤醒都需要操作系统来实现,进程需要从用户态切换为内核态。

Synchronized 锁升级

在 JVM 中,每个对象都有一个对象头,对象头中的 Mark Word 标记着锁的状态。

无锁

当一个对象被创建后,没有线程进入,此时对象处于无锁状态,

偏向锁

当锁处于无锁状态时,一个线程尝试获取锁时,会以 CAS 的方式修改其中的标志位,将自己的线程 ID 记录到 Mark Word 中。线程访问该资源时,只需要判断 Mark Word 中的线程 ID 和当前线程 ID 是否一致。

轻量级锁

在偏向锁的基础上,若另一个线程访问该资源,此时Mark Word 中存储的线程 ID 与当前线程 ID 不同,就会通过自旋锁的方式获取该锁,升级为轻量级锁。

重量级锁

轻量级锁采用自适应自旋,根据历史数据等信息判断自旋次数。若线程自旋一定次数后,仍然未获得锁,则升级为重量级锁。线程进入阻塞队列,等待锁的释放。