并发编程之synchronized详解
2022-03-20 22:01:54 1 举报
登录查看完整内容
并发编程之synchronized详解
作者其他创作
大纲/内容
实现
monitorenter
暂停原持有偏向锁的线程
偏向锁
0/1标志
转变为重量级锁指向重量级锁Monitor的指针10
原持有偏向锁的线程栈中分配锁记录
多个线程同时访问
检查方法的ACC_SYNCHRONIZED 访问标志是否被设置
执行同步块方法体
同步对象Object
AQS
线程执行monitorenter指令时尝试获取monitor的所有权
方法的同步
执行monitorexit的线程必须是该monitor的占用者
失败
否
不是
sychronized无锁状态
存在Mark Word 里
TreadlD
锁的膨胀升级过程
轻量级锁
对象
对象分代年龄
监听器monitor
无锁状态
GC标记
偏向锁状态
2、如果线程已经占用该monitor,只是重新进入,进入数加1
进入Owner区域并把monitor中的owner变量设置为当前线程,同时count+1
开始偏向锁撤销(等待竞争时才释放锁的机制)
手动设置‐XX:+UseCompressedOops
从安全点继续执行
当前线程
可重入
是
Epoch
原持有偏向锁的线程到达安全点
monitor
01
获得轻量级锁,指向当前线程的锁记录的指针00
未退出同步代码块
对象锁轻量级锁
1
进入WaitSet集合中等待被唤醒
Monitor.Exit后,出队再尝试获取锁
jdk<1.6
monitorexit
唤醒原持有偏向锁的线程
检查对象的Markword中记录的是否当前线程ID
可变:资源可以在其生命周期内被访问
64-32
成功
OPP
拷贝对象头的Markword到原持有偏向锁的线程的锁记录上
sychronized内置锁
锁的升级优化
这些局部变量是在每个线程的私有栈中,不具备共享性,不会有线程安全
monitor被占用,就处于锁定状态
Monitor(监听器)
指向线程栈中锁记录的指针
4Bit
_WaitSet和_EntryList:用来保存ObjectWaiter对象列表
目前锁状态?
检查原持有偏向锁的线程的状态
释放锁
Lock
是否是偏向锁
原持有偏向锁的线程释放锁0 01
设计同步器的意义
JVM根据该提示符来实现方法的同步
Data N
2Bit
对象锁偏向锁
临界资源:有可能是对象,变量,文件等
无锁
同步队列(SynchronizedQueue)
1Bit
锁标记位
获得偏向锁01
指向重量级锁Monitor的指针(依赖Mutex操作系统的互斥)
Markword00
释放monitor(锁)并复位count值
MetaData元数据指针
同步对象
对象的HashCode
11
失败一定次数后
Markword1 01
CAS操作替换成当前线程ID
原持有偏向锁的线程获得轻量级锁,指向原持有偏向锁的线程的锁记录的指针00
多线程编程中,有可能出现多个线程同时访问同一个共享、可变资源的情况
在当前线程栈中分配锁记录
先释放偏向锁
不同点
10
指向持有ObjectWaiter对象的线程
线程ID
Mark Word32位
mutex挂起当前线程
编译成字节码后翻译
当多个线程访问同个方法时,该方法内部的局部变量并不是临界资源
3、同步代码块,锁是括号里面的对象
对象Object
sychronized
实例数据
执行方法体,执行完后释放monitor
执行线程先获取monitor
Markword10
获取成功后
重量级锁
数组长度
线程1
目的
设置了
自旋
执行同步代码块
CAS操作将对象头的Markword的所记录指针指向当前线程的锁记录上
线程访问同步代码块
没有两个指令
3、如果其他线程已经占用该monitor,则该线程进入阻塞状态,知道monitor进入数为0,再重新尝试获取monitor的所有权
轻量级锁00
升级为轻量级锁
CAS操作1&21、对象头中的Mark Word中锁记录指针是否仍然指向当前 线程锁记录2、拷贝在当前线程锁记录的Mark Word信息是否与对象头中的Mark Word一致
字节码反编译
Pthread_操作系统维护
基于JVM内置锁实现,通过内部对象Monitor(监听器)实现,基于进入与退出Monitor对象实现方法与代码块同步
指令执行,monitor进入数减一,如果减一后进入数为0,则线程退出monitor,不再是这个monitor的所有者
唤醒被挂起的那些线程
synchronized
同步器的本质
轻量级锁状态
线程2
MarkWord锁标识位为10
空
重量级锁状态
检查偏向标志
公平性
实现方式
同步代码逻辑
重量级锁OS->Mutex(互斥锁)(竞争非常激烈)
执行完毕
获得偏向锁,把线程ID指向自己
0
通常描述为对象
采用序列化访问临界资源(即在同一时刻,只能有一个线程访问临界资源)(同步互斥访问)
开启轻量级锁解锁
释放当前持有的monitor
底层原理
锁状态
ObjectMonitor数据结构
共享:资源可以由多个线程同时访问
解决方案
过程
加锁
首先进入EntryList集合
Monitor.Enter
线程调用wait()方法
访问同步块
拷贝对象头的Markword到锁记录上
Monitor.Enter失败
2、同步类方法,锁是当前类对象(static)
Mark Word32bit
对齐填充(选填)
doug li
开始新一轮锁竞争
原偏向锁线程
每个等待的线程都会被封装成ObjectWaiter对象
java对象new Object
升级为重量级锁
25Bit
monitorexit指令出现两次,第一次为同步正常退出释放锁;第2次发送异步退出释放锁
ReentrantLock(java语言写的)
常量池多了ACC_SYNCHRONIZED
导致用户态和内核态之间切换,对性能有大影响
对象锁,锁的是对象,而非引用,作用粒是对象,可以来实现对临界资源的同步互斥访问,是可重入的
00
调用过程
锁状态标志01
获得对象Monitor
未活动状态/已退同步代码块
hascode
指针指向Monitor对象的起始地址
Monitor.Enter成功
重量级锁10
jdk>=1.6
Markword001
age
1、同步实例方法,锁是当前实例对象
偏向状态0或1
对象头
其他线程就可以尝试访问该monitor
对齐填充位
调用hashcode
23Bit
是否偏向
两个指令执行是JVM通过调用操作系统的互斥原语mutex来实现
0 条评论
回复 删除
下一页