java并发编程-synchronized(1)

138 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

什么是锁

互斥:规定同一时间内多个线程只能有一个线程能够持有监视器,其他线程不能进入由监视器保护的同步块,直到那一个线程退出监视器

可见性:当获取锁的时候,线程的CPU会强制从主存中获取最新值,当释放锁的时候,会将CPU的缓存行刷回主存中。

下图为sync的hapends-before关系图

红线为监视器锁规则推导,蓝线为程序顺序推导。

这样意味着线程A的操作对线程B是可见的,前面线程执行的结果对后面线程是可见的,那么对于线程来说就是线程间相互通信

synchronized的happens-before关系.png

monitor

基于进出ObjectMonitor对象来实现同步。任何对象都有monitor。

  • 同步代码块:使用monitorentermonitorexit指令实现。

    • 在编译后monitorenter插入到同步代码块的开始位置

    • monitorexit插入到同步代码块结束位置异常位置

image-20220303230231264.png

同步方法:编译中flags指定为ACC_SYNCHRONIZED,那么线程在执行方法前会先去获取monitor对象

什么是monitor

操作系统的管程,一种同步机制,管理多线程互斥访问共享资源,即同一时间点,只有一个线程能够访问共享资源。ObjectMonitor是其实现。

对象存在着一个monitor与其对应->Objectmonitrot对象,将mark word存储指向这个对象的地址,将mark word锁标志为设置为10

下图为ObjectMonitor对象的属性。

image-20220309164740949.png

  • _header : 存放对象的mark word的hashCode,分代年龄,偏向锁标志为等信息30bit

  • _owner : 指向当前持有锁的线程

  • _recursions:锁重入的次数

  • _count:用来记录该线程获取锁的次数。调用monitorenter使其+1,monitorexit使其-1

  • _waitSet(等待队列)

    • waitSet用于存储调用wait() 等待唤醒的线程。当调用wait()后释放锁,将该线程存入waitSet中,当线程被notify()通知,就会进入EntrySet竞争锁。因为每一个对象都能当锁,因此wait和notify是Object的方法
  • _EntryList(阻塞(同步)队列)

    • EntrySet用于存储等待竞争锁的线程