五分钟弄懂synchronized锁升级过程

synchronized锁升级过程

在JDK1.6以前,使用synchronized就只有一种方式即重量级锁,而在JDK1.6以后,引入了偏向锁,轻量级锁,重量级锁,来减少竞争带来的上下文切换。


前菜

Java对象头

每个对象都拥有对象头,对象头由Mark World ,指向类的指针,以及数组长度三部分组成

Mark World 记录了对象和锁有关的信息,在64位JVM中Mark World的长度是64bit 具体结构如下:

锁升级主要依赖Mark Word中的锁标志位和释放偏向锁标识位。

用户态和内核态

内核态

CPU可以访问内存所有数据,包括外围设备,例如硬盘,网卡。CPU也可以将自己从一个程序切换到另一个程序

用户态

只能受限的访问内存,切不允许访问外围设备。占用CPU的能力被剥夺,CPU资源可以被其他程序获取。

之所以会有这样的却分是为了防止用户进程获取别的程序的内存数据,,或者获取外围设备的数据。

什么时候进行切换

用户程序都是运行在用户态的,但是有时候程序确实需要做一些内核的事情,例如从硬盘读取数据,或者从硬盘获取输入,而唯一可以做这些事情的就是操作系统(synchronized中依赖的monitor也需要依赖操作系统完成,因此需要用户态到内核态的切换)所以程序就需要先操作系统请求以程序的名义来执行这些操作。

这时候就需要:将用户态程序切换到内核态,但是不能控制在内核态中执行的命令 这部分先不做太多解释,需要知道的是synchronized是依赖操作系统实现的,因此在使用synchronized同步锁的时候需要进行用户态到内核态的切换。
参考链接

synchronized 内核态切换

简单来说在JVM中monitorenter和monitorexit字节码依赖于底层的操作系统的Mutex Lock来实现的,但是由于使用Mutex Lock需要将当前线程挂起并从用户态切换到内核态来执行,这种切换的代价是非常昂贵的。

主菜->锁升级过程

synchronized锁的四种状态分别是:无锁状态->偏向锁->轻量级锁->重量级锁。
锁只能升级不能降级,但偏向锁可以重置成无锁的状态。

偏向锁

线程1获取锁对象时,会在java对象头和栈帧中记录偏向的锁的threadID。

线程1获取该锁时,比较threadID是否一致 ------- 一致 -> 直接进入而无需使用CAS来加锁、解锁。

线程2获取该锁时,比较threadID是否一致 ------- 不一致 -> 检查对象的threadID线程是否还存活。

存活:代表该对象被多个线程竞争,于是升级成轻量级锁。
不存活:将锁重置为无锁状态,锁头重新标记线程2为新的threadID

优势
通过加偏向锁的方式可以看到,对象中记录了获取到对象锁的线程ID,这就意味如果短时间同一个线程再次访问这个加锁的同步代码或方法时,该线程只需要对对象头Mark Word中去判断一下是否有偏向锁指向它的ID,不需要在进入Monitor去竞争对象了。

轻量级锁

轻量级锁意味着标示该资源现在处于竞争状态。
当有其他线程想访问加了轻量级锁的资源时,会使用自旋锁+CAS锁优化,来进行资源访问。

自旋策略
JVM 提供了一种自旋锁,可以通过自旋方式不断尝试获取锁,从而避免线程被挂起阻塞。这是基于大多数情况下,线程持有锁的时间都不会太长,毕竟线程被挂起阻塞可能会得不偿失。

从 JDK1.7 开始,自旋锁默认启用,自旋次数由 JVM 设置决定,这里不建议设置的重试次数过多,因为 CAS 重试操作意味着长时间地占用 CPU。自旋锁重试之后如果抢锁依然失败,同步锁就会升级至重量级锁,锁标志位改为 10。在这个状态下,未抢到锁的线程都会进入 Monitor,之后会被阻塞在 _WaitSet 队列中。

重量级锁

自旋失败,很大概率 再一次自选也是失败,因此直接升级成重量级锁,进行线程阻塞,减少cpu消耗。

当锁升级为重量级锁后,未抢到锁的线程都会被阻塞,进入阻塞队列。

获取锁的同时会阻塞其他正在竞争该锁的线程,依赖对象内部的监视器(monitor)实现,monitor又依赖操作系统底层,需要从用户态切换到内核态,成本非常高。

总结

synchronized锁升级实际上是把本来的悲观锁变成了 在一定条件下 使用无所(同样线程获取相同资源的偏向锁),以及使用乐观(自旋锁 cas)和一定条件下悲观(重量级锁)的形式。

偏向锁:适用于单线程适用锁的情况

轻量级锁:适用于竞争较不激烈的情况(这和乐观锁的使用范围类似)

重量级锁:适用于竞争激烈的情况

慢慢把知识整理起来,形成自己的知识树,早日进大厂!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值