大白话讲解synchronized锁升级套路

简介: synchronized锁是啥?锁其实就是一个对象,随便哪一个都可以,Java中所有的对象都是锁,换句话说,Java中所有对象都可以成为锁。 这次我们主要聊的是synchronized锁升级的套路

synchronized锁是啥?锁其实就是一个对象,随便哪一个都可以,Java中所有的对象都是锁,换句话说,Java中所有对象都可以成为锁。 这次我们主要聊的是synchronized锁升级的套路
synchronized会经历四个阶段:无锁状态、偏向锁、轻量级锁、重量级锁 依次从耗费资源最少,性能最高,到耗费资源多,性能最差。
锁原理
先看看这些状态的锁为什么称之为锁,他们的互斥原理是啥。
偏向锁
当一个线程到达同步代码块,尝试获取锁对象的时候,会查看对象头中的MarkWord里的线程ID,如果这里没有ID则将自己的保存进去,拿到锁。若是有,则查看是否是当前线程,如果不是,就CAS尝试改,如果是,就已经拿到了锁资源。
这里详细说说CAS尝试修改的逻辑:它会检查持有偏向锁的线程状态。首先遍历当前JVM的所有存活的线程,如果能找到偏向的线程,则说明偏向的线程还存活,此时会检查线程是否在执行同步代码块中的代码,如果是,则升级为轻量级锁,去继续进行CAS竞争锁。所以加了偏向锁之后,同时只有一个线程可以拿到锁执行同步代码块中的代码。
轻量级锁
查看对象头中的MarkWord里的Lock Record指针指向的是否是当前线程的虚拟机栈,如果是,拿锁执行业务,如果不是则进行CAS,尝试修改,若是修改几次都没有成功,再升级到重量级锁。
重量级锁
查看对象头中的MarkWord里的指向的ObjectMonitor,查看owner是否是当前线程,如果不是,扔到ObjectMonitor里的EntryList中排队,并挂起线程,等待被唤醒。
锁升级
无锁
一般情况下,新new出来的一个对象,暂时就是无锁状态。因为偏向锁默认是有延迟的,在启动JVM的前4s中,不存在偏向锁,但是如果关闭了偏向锁延迟的设置,new出来的对象,就会添加一个匿名偏向锁。也就是说这个对象想找一个线程去增加偏向锁,但是没有找到,称之为匿名偏向。存储的线程ID为一堆0000,也没有任何地址信息。
我们可以通过以下配置关闭偏向锁延迟。
java复制代码//关闭偏向锁延迟的指令
-XX:BiasedLockingStartuoDelay=0

偏向锁
当某一个线程来获取这个锁资源时,此时会成功获取到,就会变为偏向锁,偏向锁存储线程的ID。
当偏向锁升级时,会触发偏向锁撤销,偏向锁撤销需要等到一个安全点,比如GC的时候,偏向锁撤销的成本太高,所以默认开始时,会做偏向锁延迟。若是直接有多个线程竞争,会跳过偏向锁,直接变为轻量级锁。

细说一下偏向锁撤销的过程,成本为啥高呢?当一个线程拿到偏向锁之后,会把锁的对象头的Mark Work中的线程id指向自己,当又有一个线程来了进行争抢导致锁升级的的时候,会暂停之前拿到偏向锁的线程,然后清空Mark Work中的线程id,增加一个轻量级锁,然后再恢复暂停的线程继续执行。这也是为什么等到安全点再执行锁升级的原因,因为要暂停线程。

常见的安全点:

执行GC的时候
方法返回之前
调用某个方法之后
抛出异常的位置
一个循环的末尾

轻量级锁
当在出现了多个线程的竞争,就会升级为轻量级锁,轻量级锁的效果就是基于CAS尝试获取锁资源,这里会用到自适应自旋锁,根据上次CAS成功与否,耗费的时间,决定这次自旋多少次。
轻量级锁适用于竞争不是很激烈的场景,一个线程拿到锁,执行同步代码块,很快就处理完了。再来一个线程尝试一两次也拿到了锁,再去执行,不会让一个线程等待很久。
重量级锁
如果到了重量级锁,那就没啥说的了,如果有线程持有锁,其他想拿锁的就挂起,等待锁释放后被依次唤醒。
锁粗化&锁消除
锁粗化/锁膨胀
锁膨胀是编译Java文件的时候,JIT帮我们做的优化,它会减少锁的获取和释放次数。
比如:
java复制代码while(){
synchronized(){

  // 多次的获取和释放,成本太高,会被优化为下面这种

}
}
synchronized(){
while(){

   //  拿到锁后执行循环,只加锁和释放一次

}
}

锁消除:
锁消除则是在一个加锁的同步代码块中,没有任何共享资源,也不存在锁竞争的情况,JIT编译时,就直接将锁的指令优化掉。
比如
java复制代码synchronized(){
int a = 1;
a++;
//操作局部变量的逻辑
}

相关文章
|
7月前
|
存储 监控 安全
吃透synchronized实现原理
吃透synchronized实现原理
96 0
|
4月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
92 5
|
2月前
|
存储 安全 Java
面试题:再谈Synchronized实现原理!
面试题:再谈Synchronized实现原理!
|
4月前
|
Java
【多线程面试题十三】、说一说synchronized与Lock的区别
这篇文章讨论了Java中`synchronized`和`Lock`接口在多线程编程中的区别,包括它们在实现、使用、锁的释放、超时设置、锁状态查询以及锁的属性等方面的不同点。
|
6月前
|
安全 Java 开发者
一文弄懂synchronized
一文弄懂synchronized
87 0
|
7月前
|
Java API 调度
大厂高频面试题:ReentrantLock 与 synchronized异同点对比
【5月更文挑战第7天】大厂高频面试题:ReentrantLock 与 synchronized异同点对比
73 0
|
设计模式 安全 Java
JUC第十二讲:JUC锁 - 看不懂锁核心类 AQS 原理来打我
JUC第十二讲:JUC锁 - 看不懂锁核心类 AQS 原理来打我
|
存储 Java
【一文读懂】 Java并发 - 锁升级原理
Java对象头,锁升级的原因,重量级锁、轻量级锁、偏向锁的原理
433 0
【一文读懂】 Java并发 - 锁升级原理
|
Java C++
说一下 synchronized 底层实现原理?(高薪常问)
说一下 synchronized 底层实现原理?(高薪常问)
117 2
|
Java 编译器
synchronized 和 volatile 的区别是什么?(高薪常问)
synchronized 和 volatile 的区别是什么?(高薪常问)
92 2