Java 的 synchronized 底层原理

原理

synchronized 是 Java 中的一个关键字,主要解决的是多个线程之间访问资源的同步性,其实就是充当锁的功能

synchronized实现原理依赖于JVM 的 Monitor(监视器锁)和 对象头(Object Header)

当使用 synchronized 时,实际上是通过字节码指令 monitorentermonitorexit 来实现加锁和解锁操作的。

  1. monitorenter 指令

    • 当线程执行到 synchronized 修饰的代码块时,JVM 会在字节码中插入 monitorenter 指令。

    • 在执行代码块前尝试获取指定对象的Monitor锁。如果该对象的锁计数器为 0 ,则尚未被其他线程持有,则当前线程可以成功获取锁,计数器+1,从而实现可重入性,并继续执行同步代码块。

    • 如果锁已被其他线程持有,则当前线程将会被阻塞,直到锁被释放。

  2. monitorexit 指令

    • synchronized 代码块的结尾处,JVM 会插入 monitorexit 指令。

    • monitorexit 指令负责释放之前获取的锁。当线程执行完同步代码块后,会执行 monitorexit 指令,释放所持有的锁。

      • 如果在执行同步代码块的过程中发生了异常,JVM 也会确保 monitorexit 指令被执行,以防止锁被永久持有,从而导致死锁或其他并发问题。

这也就解释了为什么synchronized 出同步块后 会自动释放锁

深入到源码来说,synchronized的内部实际上有两个队列waitSetentrySet

  1. 当多个线程进入同步代码块时,首先进入entryList

  2. 有一个线程获取到 monitor 锁后,就赋值给当前线程,并且计数器+1

    • 若线程调用wait方法,将释放锁,当前线程置为null,计数器-1,同时进入waitSet等待被唤醒

    • 若线程调用notify或者notifyAll之后又会进入entryList 竞争 monitor锁

  3. 如果线程执行完毕,同样释放锁,计数器-1,当前线程置为null

synchronized 支持重入吗?如何实现的?

可重入,底层是利用操作系统mutex Lock实现的,每一个可重入锁都会关联一个线程ID和一个锁状态status。

当一个线程请求方法时,会去检查锁状态。

  1. 如果锁状态是0,代表该锁没有被占用,使用CAS操作获取锁,将线程ID替换成自己的线程ID。

  2. 如果锁状态不是0,代表有线程在访问该方法。此时如果线程ID是自己的线程ID,会将status自增1,然后获取到该锁

  3. 释放锁时同理,可重入锁的,每一次退出方法,就会将status减1,直至status的值为0,最后释放该锁。

锁的升级和优化

在 Java 6 之后,JVM 引入了偏向锁和轻量级锁,重量级锁等优化技术

具体的锁升级的过程是:无锁->偏向锁->轻量级锁->重量级锁

总结

  • 偏向锁: 当一个线程第一次获取锁时,JVM 会将该线程标记为“ 偏向 ”状态,后续若该线程再获取该锁,无需进行额外同步过程。

  • 轻量级锁: 当另一个线程尝试获取已经被偏向的锁时,锁会升级为轻量级锁,使用CAS 操作来减少锁竞争的开销。

  • 重量级锁: 当 CAS 失败无法获取锁,锁会升级为重量级锁,线程会被挂起,直到锁被释放。

Monitor 的内部结构

在 Monitor 的内部,有两个队列:等待队列(Wait Queue)和条件等待队列(Condition Queue)

  • 未获得锁的线程会被放置在等待队列中,而那些调用了 wait() 方法的线程会被移到条件等待队列中。

  • 当锁被释放或调用了 notify()notifyAll() 方法时,相应的队列中的线程会被唤醒,尝试获取锁。

自适应自旋锁
  • 为了减少重量级锁带来的上下文切换开销,JVM 引入了自适应自旋锁机制。在轻量级锁阶段,如果线程发现锁未被占用,它会尝试循环(自旋)一段时间,希望在此期间锁能被释放。

  • 自旋的时间长度可以根据前一次自旋等待锁的成功率来动态调整,这样可以在一定程度上提升锁的性能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

空说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值