同步概念
对象
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/0b939d0622925e7ce05abb19c436f547.png)
- 实例数据: 存放类的属性数据信息,包括父类的属性信息
- 对齐填充: 由于虚拟机要求 对象起始地址必须是
8字节的整数倍
,填充数据不是必须存在的,仅仅是为了字节对齐
- 对象头: Java对象头一般占有2个机器码(在32位虚拟机中,1个机器码等于4字节,也就是32bit,在64位虚拟机中,1个机器码是8个字节,也就是64bit),但是 如果对象是数组类型,则需要3个机器码,因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小,但是无法从数组的元数据来确认数组的大小,所以用一块来记录数组长度
对象头
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1b495a3684202cf82927d6f8695513ad.png)
- Class Pointer: 是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
- Mark Word: 用于存储对象自身的运行时数据,它是实现轻量级锁和偏向锁的关键
- Array Length: 数组长度
Mark Word
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ebfe035e872ce6696d50f1d19094ece8.png)
线程中的Lock Record
- Owner: 初始时为NULL表示当前没有任何线程拥有该monitor record,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULL
- EntryQ: 关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor record失败的线程
- RcThis: 表示blocked或waiting在该monitor record上的所有线程的个数
- Nest: 用来实现 重入锁的计数
- HashCode: 保存从对象头拷贝过来的HashCode值(可能还包含GC age)
- Candidate: 用来避免不必要的阻塞或等待线程唤醒,因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。Candidate只有两种可能的值0表示没有需要唤醒的线程1表示要唤醒一个继任线程来竞争锁
Monitor
ObjectMonitor() {
_header = NULL;
_count = 0; // 记录个数
_waiters = 0,
_recursions = 0;
_object = NULL;
_owner = NULL;
_WaitSet = NULL; // 处于wait状态的线程,会被加入到_WaitSet
_WaitSetLock = 0 ;
_Responsible = NULL ;
_succ = NULL ;
_cxq = NULL ;
FreeNext = NULL ;
_EntryList = NULL ; // 处于等待锁block状态的线程,会被加入到该列表
_SpinFreq = 0 ;
_SpinClock = 0 ;
OwnerIsThread = 0 ;
}
- Monitor对象存在于每个Java对象的对象头
Mark Word
中(存储的指针的指向)
- ObjectMonitor中有两个队列,
_WaitSet
和_EntryList
,用来保存ObjectWaiter对象列表( 每个等待锁的线程都会被封装成ObjectWaiter对象
),_owner指向持有ObjectMonitor对象的线程
- 当多个线程同时访问一段同步代码时,会先存放到
_EntryList
集合中,接下来当线程获取到对象的monitor时,就会把_owner
变量设置为当前线程,同时count
变量+1
- 如果线程调用