synchronized
2022-07-22 01:15:55 2 举报
synchronized详情
作者其他创作
大纲/内容
线程非存活退出同步代码块
获得偏向锁记录线程ID
1. synchronized主要保证在多线程下,数据的一致性,同一时刻只能有一个线程操作共享变量,线程之前互斥2. 在线程解锁时,会将共享变量的值强制刷新到主内存,线程加锁时,会将CPU缓存设置过期,重新到主内存拉取最新共享变量
锁的种类及原理
java对象结构
获得轻量级锁执行业务代码
当前执行线程
锁升级过程
MarkWork
类型指针
数组长度(如果是数组对象)
未退出同步代码块
自旋适应锁自旋锁是指通过自身循环,尝试获取锁的一种方式。优点在与它能避免一下线程的挂起和恢复操作,因为挂起线程和恢复线程需要从用户态切换到内核态浪费CPU性能,所以通过自旋的方式一定程度的避免性能开销对于sync关键字来说,它的自旋更加的 \"智能\" sync中的自旋锁是自适应自旋锁自适应自旋锁是指,线程自旋的次数不再是固定的值,而是一个动态可改变的值,这个值会根据前一次自旋获取锁的状态来决定此次自旋的次数。比如上一个通过自旋成功获取到的了锁,那么这次通过自旋也可能会获取到锁,所以自旋的次数会增多一些,而如果上一次通过自旋没有成功获取到锁,怎么这次自旋可能也获取不到锁,所以为了避免浪费资源,就会减少循环或者不循环,提供程序的执行效率。简单来说,如果自旋成功了,下次自旋次数增多,如果失败,下次自旋次数减少或者自旋
锁粗化某些情况下,一系列连续的加锁解锁操作,会导致不必要的性能开销,锁粗化是指,将多个连续的加锁、解锁操作连接在一起,扩大了范围。(增大了锁作用域,合并成一个更大的锁)
获得轻量级锁
锁状态
优点
缺点
使用场景
偏向锁
加锁、解锁没有额外消耗。和执行非同步方法仅有秒级差别
如果线程间存在锁竞争,会有额外锁撤销的性能
基本没有线程竞争,多数为一个线程同步访问场景
轻量级锁
竞争线程不会阻塞,适应CAS自旋,提供了程序响应速度
如果无法获取到锁,长时间自旋会消耗CPU资源
锁持有时间短,追求响应速度
重量级锁
线程不会适应自旋,不会导致CPU空转
线程阻塞,响应慢
追求吞吐量,锁持续时间长
执行业务代码
升级重量级锁
lock中的markord标识的线程ID是否是当前线程(锁重入)
判断状态
指向重量级锁monitor指针
jvm启动偏向线程默认打开,但是偏向锁启动是有延迟的(4000ms)jvm参数:-XX:BiasedLockingStartupDelay=4000
无锁
成功
自旋
实例数据
轻量级锁:考虑的是竞争的线程不是很多,且持有锁的时间短的场景。因为线程阻塞需要CPU从用户态切换到内核态,如果线程刚阻塞不就,锁就释放了,那这个代价有点大。所以干脆不阻塞这个线程,让它进行自旋等待锁释放
A线程访问代码块获取到锁对象之后,会在java对象头的栈帧记录偏向锁的请求线程ID因为偏向锁不会主动释放,所以A线程再次获取到锁的时候,需要比较A线程的ThreadID是否和对象头中的线程ID是否一致 1. 一致:锁重入A线程继续获取锁,无需使用CAS加锁、解锁 2. 不一致:说明有其他线程B来竞争锁对象,由于偏向锁不会主动释放锁对象,对象头存储的A线程线程ID,那么需要对象记录判断线程A是否存活 (1)如果没有存活,那么锁对象被重置为无锁状态(锁撤销),线程B设置偏向锁 (2)如果存活,立即查找线程A的栈帧信息,如果线程A还需要继续持有锁,那么暂停线程A(stw),撤销A的偏向锁升级为轻量级锁,如果不需要持有锁,锁对象重置为无锁状态,锁偏向线程B
sync不管是修饰代码块还是方法,都是通过对对象的锁来实现同步。而sync锁对象存在于锁住的对象头MarkWork中
偏向锁撤销恢复无锁
失败
当前线程挂起阻塞
markword存储偏向锁的线程ID
锁消除在某些情况下,对于某段代码不存在锁竞争和共享的可能性,就会把锁消除,达到提供性能的目的
经量/重量锁
对象头
作用
持有偏向线程暂停(stw)
markword存储指向线程栈中的LockRecord的指针
否
CAS操作对象头markword锁记录指针指向当前线程锁记录
对象
markword存储指向堆中的monitor对象的指针
stw线程唤醒从安全点继续执行
start
A线程获得轻量级锁之后,会把锁对象的对象头MarkWord复制一份到线程A的栈帧中创建用于存储锁记录的空间(DisplacedMarkWord),然后使用CAS自旋把对象头中的内容替换为A线程存储锁记录的地址如果A线程在复制对象头的过程中(CAS替换前),C线程也获取了锁,复制了锁对象头到C线程的锁记录空间,在执行CAS自旋做对象头内容替换的时候,发现A线程已经更改了对象头,则C线程替换失败,尝试自旋等待A线程释放锁自旋要消耗CPU会影响性能,所以不能无限制的自旋下去,因为自旋次数有限制(10次),如自旋次数到了,A线程还没有释放锁,C线程在自旋等待,D线程又来竞争锁,这个时候经量级锁会升级为重量级锁。重量级锁把除A线程之外的,前来竞争锁的线程全部阻塞,防止CPU空转
持有偏向锁的线程到达安全点
是
是否是偏向锁
检查持有偏向锁的线程状态
执行偏向锁撤销(锁竞争开始,释放锁的机制)
持有偏向锁线程中分配锁记录(lockRecord)拷贝锁对象头中markword到持有偏向线程的lockRecord中
CAS操作(自旋)更新markwork标识的线程ID
是否原持有偏向锁线程
偏向锁:因为经过大量的研究发现,大多数不存在锁竞争的,经常是一个线程在持有锁,由于每次竞争锁会有很大的性能开销,为了降低锁的代价,从而引入偏量锁
继续尝试
自旋10次未未获取到锁
有锁
消费者处理mes1突然失去连接没有返回ACK确认消息
对齐填充-8字节倍数
synchronized
0 条评论
下一页