synchronized同步的位置:
1、普通同步方法,锁是当前实例对象;
2、静态同步方法,锁是当前类的class对象;
3、同步方法块,锁是括号里面的对象。
synchronized存于Java对象头中
虚拟机的对象头主要包括两部分数据:Mark Word(标记字段)、Klass Pointer(类型指针)。
Mark Word:存储对象自身的运行时数据
例如:哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等
当Java对象头的Mark Word发生锁升级时,非固定长度的Mark Word数据结构也会发生改变
Klass Point:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例
Java对象头储存结构:
synchronized的同步机制Monitor
每一个Java对象出生自带Monitor锁,所以每个Java对象都可以成为Monitor
在线程中,Monitor时线程私有的数据结构
每一个线程都会有一个可用的monitor record列表和一个全局的可用列表,将被加锁对象与monitor锁关联**(对象头的MarkWord中的LockWord指向monitor的起始地址)**,同时monitor锁中存放该线程的唯一标识id,以表示该锁被某个线程占用,以此实现同步机制
Monitor列表结构
Owner:初始时为NULL表示当前没有任何线程拥有该monitor record,当线程成功拥有该锁后保存线程唯一标识,当锁被释放时又设置为NULL。
EntryQ:关联一个系统互斥锁(semaphore),阻塞所有试图锁住monitor record失败的线程。
RcThis:表示blocked或waiting在该monitor record上的所有线程的个数。
Nest:用来实现重入锁的计数。HashCode:保存从对象头拷贝过来的HashCode值(可能还包含GC age)。
Candidate:用来避免不必要的阻塞或等待线程唤醒,因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。
Candidate只有两种可能的值0表示没有需要唤醒的线程1表示要唤醒一个继任线程来竞争锁。