关于synchronized的底层实现原理,锁的优化,及锁的四种状态

本文详细解析了synchronized关键字的实现机制及其优化策略,包括自旋锁、自适应自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等概念,并对比了synchronized与j.u.c.Lock的不同,深入探讨了锁的四种状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

synchronized在1.5之前是个重量级锁。但是从JDK6开始,就对synchronized的实现机制进行了较大调整,包括使用JDK5引进的CAS自旋之外,还增加了自适应的CAS自旋、锁消除、锁粗化、偏向锁、轻量级锁这些优化策略。由于此关键字的优化使得性能极大提高

synchronized是在软件层面依赖JVM,而j.u.c.Lock是在硬件层面依赖特殊的CPU指令。

一,

1,synchronized同步块的使用是给出一个对象锁,每个对象锁都是一个监视器锁(monitor)

1,monitorenter   当monitor被占用时就会锁定,线程就会尝试执行monitorenter,获取monitor的所有权。
MonitorEnter指令:插入在同步代码块的开始位置,当代码执行到该指令时,将会尝试获取该对象Monitor的所有权,即尝试获得该对象的锁;
2,monitorexit     执行monitorexit的线程必须是对象锁所对应的monitor的所有者。指令执行时,monitor的进入数减1,如果减1后进入数为0,那线程退出monitor,不再是这个monitor的所有者。其他被这个monitor阻塞的线程可以尝试去获取这个 monitor 的所有权。
	插入在方法结束处和异常处,JVM保证每个MonitorEnter必须有对应的MonitorExit;

1,synchronized在方法上是通过检查常量池中是否ACC_SYNCHRONIZED 标示符

	当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,
	如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。
	在方法执行期间,其他任何线程都无法再获得同一个monitor对象。

所以,由此可见synchronized的语意底层是

(Synchronized的语义底层是通过一个monitor的对象来完成,
其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,
否则会抛出java.lang.IllegalMonitorStateException的异常的原因。)

二,自旋锁,自适应自旋锁,锁消除与锁粗化

线程的阻塞和唤醒需要CPU从用户态转为核心态,频繁的阻塞和唤醒对CPU来说是一件负担很重的工作

自旋锁

	自旋锁,就是指当一个线程尝试获取某个锁时,如果该锁已被其他线程占用,就一直循环检测锁是否被释放,而不是进入线程挂起或睡眠状态。
	这时候临界时间很短的情况下。
	自旋等待不能替代阻塞,虽然它可以避免线程切换带来的开销,但是它占用了CPU处理器的时间。
	如果持有锁的线程很快就释放了锁,那么自旋的效率就非常好。时间长的话只会白白浪费性能,
	所以自旋锁一旦超过一定次数,应该被挂起。

自适自旋锁

	如果一次自旋锁成功了,那么下次自旋的次数会更加多。
	反之,如果对于某个锁,很少有自旋能够成功,那么在以后要或者这个锁的时候自旋的次数会减少甚至省略掉自旋过程,以免浪费处理器资源。

锁消除

	JVM检测到不可能存在共享数据竞争,这时JVM会对这些同步锁进行锁消除。
	
	在使用一些JDK的内置API时,如StringBuffer、Vector、HashTable等,这个时候会存在隐形的加锁操作。比如StringBuffer的append()方法,Vector的add()方法

锁粗化

	锁粗化就是将多个连续的加锁解锁连接到一起,扩展成一个更大的锁。
	
例如:
vector每次add的时候都需要加锁操作,JVM检测到对同一个对象(vector)连续加锁、解锁操作,会合并一个更大范围的加锁、解锁操作,即加锁解锁操作会移到for循环之外。

三,锁的四种状态

无锁状态,偏向锁状态,轻量级锁状态,重量级锁状态。锁只能膨胀升级不能降级。

偏向锁状态

	在JDK5中偏向锁默认是关闭的,而到了JDK6中偏向锁已经默认开启
	现在几乎所有的锁都具有可重入性,每次加锁/解锁都会涉及到一些CAS操作
	偏向锁就是一旦一个线程获得锁,就让监视器对象偏向这个锁,之后多次加锁解锁避免cas操作。简单而言就是设置一个变量,只要为true就避免那些流程。
	偏向锁是单线程机制里使用的,如果是在多线程并发的情况下。就会膨胀为轻量级锁或者重量级锁。

轻量级锁是为了在线程交替执行同步块时提高性能,而偏向锁则是在只有一个线程执行同步块时进一步提高性能
线程是不会主动去释放偏向锁,需要等待其他线程来竞争

轻量级锁状态

	轻量级锁是在没有多线程竞争的情况下,减少传统重量级锁的消耗

重量级锁状态

	依赖于操作系统的mutexlock实现的称之为重量级锁。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值