多线程—synchronized原理
上篇文章:
多线程—锁策略https://blog.csdn.net/sniper_fandc/article/details/146508232?fromshare=blogdetail&sharetype=blogdetail&sharerId=146508232&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link
目录
1 synchronized的锁策略
2 synchronized的锁升级
3 synchronized的锁消除
4 synchronized的锁粗化
1 synchronized的锁策略
1.synchronized即是乐观锁,也是悲观锁(自适应:根据锁竞争激烈程度升级)。
2.synchronized即是轻量级锁,也是重量级锁(自适应:根据锁竞争激烈程度升级)。
3.synchronized的轻量级锁是自旋锁(基于CAS)实现,重量级锁是挂起等待锁(操作系统的mutex锁实现)。
4.synchronized是可重入锁。
5.synchronized不是读写锁,是互斥锁。
6.synchronized是非公平锁。
2 synchronized的锁升级
1.synchronized一开始采用的是无锁状态,即此时没有任何线程加锁。
2.当有线程尝试加锁时,此时synchronized升级为偏向锁,虽然名字叫锁,但此时没有加锁,只是往锁对象头加入了偏向锁标记,记录当前锁是哪个线程的,如果没有其他线程竞争锁,就不用真正的加锁,从而减少了加锁解锁的开销。如果此时有线程竞争锁,就取消偏向锁状态,进入真正的加锁状态。
3.当偏向锁进入加锁状态时,也就是进入轻量级锁,基于CAS实现的自旋锁就是轻量级锁的实现,此时锁竞争还不激烈,加锁操作仅停留在用户态。(自旋锁不是一直占有CPU的,而是自旋了一定次数后就会停止尝试获取锁的行为)
4.当锁竞争激烈时,此时自旋锁无法快速获得锁(就会一直浪费CPU资源),那就会升级为重量级锁。重量级锁是通过挂起等待锁实现的,也就是操作系统提供的mutex锁。当加锁时会进入内核态,判断是否能加锁,如果可以就加锁并切换回用户态;否则就把线程挂起等待操作系统的唤醒。
3 synchronized的锁消除
JVM和编译器底层会判断当前场景是否是线程安全的,如果是线程安全的环境下用到synchronized,就会进行锁消除,不再加锁。比如StringBuffer类是线程安全的,因为其底层的方法中用到synchronized,如果在单线程环境下,就会进行锁消除。
4 synchronized的锁粗化
锁分为细粒度(加锁范围小)和粗粒度(加锁范围大),当频繁使用细粒度锁加锁解锁时,JVM和编译器就会把多个细粒度锁优化成粗粒度锁,减少频繁的加锁解锁开销。
下篇文章:
多线程—JUC(java.util.concurrent)https://blog.csdn.net/sniper_fandc/article/details/146713322?fromshare=blogdetail&sharetype=blogdetail&sharerId=146713322&sharerefer=PC&sharesource=sniper_fandc&sharefrom=from_link