synchronized & volatile
2020-08-05 14:08:11 28 举报
多线程
作者其他创作
大纲/内容
为了防止线程的阻塞和唤醒,当前线程会不断自旋尝试获取锁,默认超过10次就升级为重量级锁
线程C
Mark Word:保存对象的hashcode,分代年龄和锁标志信息Kclass Point:对象执行它类元数据的指针
工作内存
false
1,在当前线程的栈帧中开辟一个空间叫Lock Record
栈帧
有volatile修饰的共享变量进行写操作,会多出一行lock前缀指令的汇编代码
隐式调用
cpu3
cpu4
下次直接从缓存行中读数据
对象头
cpu5
cpu2
线程A
markword中存指向栈帧中锁记录的指针
当前对象
cpu1
markword会随着锁标志位的变化而变化
当前缓存行的数据是否过期
总结:锁升级过程本质上就是在c++实现的源码里面调用不同的函数去获取锁,获取失败就调用更高级的实现
3,线程尝试使用CAS将对象头中的markword替换为指向锁记录的指针
实例对象
轻量级锁(000)
Owner
写会内存的操作会使其他cpu中缓存了该内存地址的数据失效
操作
true
执行完代码后执行monitorExit,进入数减一,为0时才会被其他线程持有
_WaitSet
monitor
栈
代码层面
1,嗅探
由缓存一致性协议(MESI)保证;
lock 指令不锁总线,锁缓存
synchronized同步代码块
_EntryList
4,JVM会利用CAS尝试把对象原本的Mark Word更新会Lock Record Record
线程B
主内存
有序性
偏向锁(101)
实例数据
替换成功当前线程得到锁,如果失败表示有竞争,该线程会自旋获取锁
Lock Record
synchronized同步方法ACC_SYNCHRONIZED
线程持有该对象对象头指向的Monitor,标志位修改为1,线程id记录在对象的Mark Word中(同一线程再次进入不需要CAS来加解锁,只需要判断线程id)
对齐填充
volatile
对象层面(synchronized用的锁存放在对象头中,针对64位JVM)
可见性
持有monitor对象的线程获得锁
重量级锁(010)
无锁(001)
执行字节码指令monitorEnter获得当前对象的所有权,进入数加一
2,判断
JMM(所有共享变量都存储在主内存上,每个线程还存在自己的工作内存,保存该线程使用的变量副本,不同线程之间不能访问工作内存的变量,变量要通过主内存来共享)
将当前缓存行设置成无效
synchronized
2,将对象的mark word拷贝到Lock Record中
线程D
处理器对这个数据做修改时,会直接从系统内存中读数据到缓存行
JVM会向当前处理器发送一条lock前缀指令,将当前处理器缓存行的数据写回到系统内存
总线
涉及用户态和内核态的转换,调用内核态里的park()和unpark()方法区加锁和解锁
锁升级(一般是不可逆的)
0 条评论
下一页