java-synchronized
2019-08-26 15:41:48 4 举报
java-synchronized
作者其他创作
大纲/内容
暂停t1
检查对象头中是否存了线程1
01
访问同步代码块
将对象头中的Markword替换为指向锁记录的指针
把对象头中的Markword存记录中
EntryList
被唤醒后加入等待
自旋
成功
有资格队列
重量级锁:依赖于底层操作系统的Mutex Lock实现,操作系统实现线程之间的切换需要从用户态到内核态的切换,切换成本非常高。一旦锁升级成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时,都会被阻塞住
cas修改MW
偏向锁
失败,因为t1已经获得
会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。
失败
Monitor监视器
将对象头的MW替换成轻量级锁
对象头-Markword(MW)
线程t2
成功获取对象监视器
偏向锁:当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储锁偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单地测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果测试成功,表示线程已经获得了锁。如果测试失败,则需要再测试一下Mark Word中偏向锁的标识是否设置成1(表示当前是偏向锁):如果没有设置,则使用CAS竞争锁;如果设置了,则尝试使用CAS将对象头的偏向锁指向当前线程。
在栈帧中创建存储锁记录的空间
monitorenter
对象头:存储了对象锁的信息
分配栈帧空间,并复制MW到栈中
monitorexit结束后选一个
lock
轻量级解锁
Waiting Queue 等待队列
对象监视:记录当前对象被使用的信息。线程等待信息。
unlock
锁膨胀-重量级
monitorexit
0
最多只有一个线程
失败,t2在争夺
轻量级锁
_cxq
获取锁执行
1
撤销偏向锁
升级为重量锁
线程t1
释放锁并唤醒等待线程
轻量级锁的获得和膨胀
没
hash
挂起
无锁
将对象头的MW中的线程ID执行自己
表示有竞争,测尝试自旋获取
没有
阻塞队列WaitSet
t1-id
尝试获取监视器
执行结束
cas替换MW
执行同步体
得到对象锁,执行synchronized代码块
指向t1的栈
Contention竞争队列
由ObjectWaiter组成的双向队列
偏向锁的获得和撤销
线程被wait
阻塞
Owner线程
恢复t1
10
执行
升级为重量
jvm在当前线程中
当前线程获取失败
轻量级加锁
jdk1.6时对synchronized进行优化。引入了自旋锁,偏向锁,轻量级和重量级锁的概念
偏向锁的释放:当其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,偏向锁的撤销,需要等待全局安全点,没有正在执行的字节码,就是stop the world。
失败后加入队列
有
用CAS
锁升级
指向重量指针
指针
发生异常
遇到同步代码块时
自旋获取
撤销
唤醒后继续争夺
获得锁
00
Synchronized是非公平锁。 Synchronized在线程进入ContentionList时,等待的线程会先尝试自旋CAS获取锁,如果获取不到就进入ContentionList
0 条评论
下一页