synchronized原理

3. synchronized原理

Preknowledge
对象头

1.基本数据类型

2.普通对象(封装类) Integer=4+8

image1

Monitor:

此对象由操作系统提供,

其结构为

Owner(指向持有Monitor的线程)

+

EntryList(保存等待的阻塞线程)

+

WaitSet(调用了wait的线程)

image3

不同对象得到的锁不一样

Synchronize重量级锁原理总结

Synchronized(obj){

//临界区代码

}

当执行到synchronized时,

会去检查obj对象的MarkWord是否关联monitor对象(操作系统提供),

如果没有,则让monitor对象指向该线程,

如果有,则加入Monitor的EntryList进行阻塞等待

轻量级锁:

轻量级锁其实更多是为了解决同一线程的多次重入问题,

轻量级锁

image6

image7

膨胀:

自旋:

线程阻塞和唤醒的开销非常高,
需要保存寄存器状态、切换堆栈、进入内核态并重新调度。
整个过程往往比临界区本身的执行时间还要长。

image9

偏向锁:

由于轻量级锁(在竞争方较少的情况下)每次锁重入都要cas操作检查,也会带来不必要的性能消耗.

如果一个对象被某个线程反复获取且没有线程竞争,就可以把这个锁“偏向”这个线程,后续再次获取时几乎不需要任何同步操作

撤销方法:

1.hashcode()

2.其他线程使用该锁对象

3.wait() & notify()

cas和id检查的区别:

1.id直接内存读取 + CPU 寄存器,
几乎不占用 CPU 时间片,也不会触发 CPU 的总线争用。

2.1 CAS 是原子操作,需要 CPU 保证总线或缓存一致性:

如果多核 CPU 上多个线程竞争,CAS 可能失败,需要自旋等待。

自旋期间 CPU 持续占用资源,不让出时间片。

2.2 所以 CAS 的开销不仅是比较,还可能引发总线争用、缓存一致性同步甚至自旋等待。

image10

批量重偏向:

锁消除