基础
内核态和用户态
系统指令分为不同执行级别,0 1 2 3,一般系统内核0级,用户3级。
Java对象头
Java对象的内存布局:对象头部(12字节)+ 数据+ 填充(凑够8字节倍数)
对象头部(12字节): 对象头(8字节) + 对象class指针(指针压缩4字节)
64位系统:对象头(8字节)
锁升级
- 偏向锁和轻量级锁:用户空间完成
- 重量级锁:调用内核完成
偏向锁
一般情况下,共享资源都是没有竞争情况的,所以并不需要加锁。
注意在多线程情况下,锁撤销会消耗很多系统资源。
自旋锁
如果这个锁有竞争,把偏向锁撤销掉,升级为自旋旋。
动作:把自己线程的LR记录在锁对象的对线头上。
自旋次数过多,消耗系统资源。
重量锁
操作系统级别的锁申请,linux mutex,cpu指令重3级到0级系统调用,线程挂起,进入等待队列,等待操作系统调用,在映射会用户空间。
锁升级:线程竞争加剧,有线程自旋超过10次或自旋线程超过CPU核数一半,但是1.6之后jvm加入了自适应自旋。
等待队列:在Synchronized源码中定义objectMonitor对象中有一个等待线程集合waitSet,去等待系统调用。
字节码实现:
重入锁
Synchronized是可重入锁。
重入次数记录必须记录,解锁几次要对应。
- 偏向锁 自旋锁->线程栈->LR+1
hashcode:偏向锁hashcode记录在LR上。
- 重量锁->objectmonitor字段上