Java并发编程03:锁的种类与实现

重量级锁的实现

重量级锁是锁最重的一种实现方式,提供了最完整的同步功能.

锁对象头中的Monitor对象: 记录锁信息

在这里插入图片描述

Java对象的锁信息记录在锁对象头中的Monitor对象,Moniter对象中持有三个引用:

  1. 等待队列_WaitList: 存储处于等待状态的线程的引用(即被锁的wait()方法阻塞的线程).
  2. 就绪队列_EntryList: 存储处于就绪状态的线程的引用.
  3. 持有锁线程标记_Owner: 存储当前持有锁线程的引用

多线程执行时要与锁对象头中的Monitor对象进行如下交互:

  • 当多线程并发访问同一个同步代码块时,这些线程首先会进入_EntryList.
  • 当线程抢到锁标记开始执行同步代码块时,Monitor中的计数器进行自增+1操作,并将_Owner引用指向当前线程.
  • 当线程执行完同步代码块释放锁时,Monitor中的计数器进行自减-1操作,若计数器计数至0,则将_Owner指向null(释放锁).
  • 若正在执行的线程调用了锁的等待wait()方法,则Monitor中的计数器进行清零操作,将当前线程移入_WaitList队列且将_Owner指向null(释放锁).
  • 若正在等待的线程被唤醒,则将被唤醒的线程移出_WaitList队列并将其放入_EntryList队列.

在这里插入图片描述

理解锁的可重入性

在Java中,同步锁是可重入的,只有同一线程调用同步方法或执行同步代码块,对同一个对象加锁时才可以重入.

当线程每次获得锁时,会在Monitor中的计数器进行自增运算,若当前线程连续多次获得同一把锁,会在Monitor中的计数器进行多次递增. 当同步代码块执行结束后,Monitor中的计数器会进行自减运算,直到所有同步代码都执行结束,Monitor中的计数器减至0时,才会释放锁标记(将_Owner置为null)

锁的类型

Java中锁的实现可以分为偏向锁,自旋锁,轻量级锁,重量级锁.锁的重量依次增加.

  1. 偏向锁
    偏向锁是一种编译解释锁.若代码的设计使得不可能出现多线程并发争抢同一把锁时,JVM会在编译时自动放弃锁的同步信息,而是通过MonitorACC_SYNCHRONIZED标记获得锁的线程.这可以避免锁的争抢和锁池状态的维护,提高效率.

  2. 轻量级锁
    偏向锁的条件不满足,亦即的确有多线程并发争抢同一锁对象时,但并发数不大时,优先使用轻量级锁.放弃锁的同步信息,而是通过MonitorACC_SYNCHRONIZED标记获得锁的线程,ACC_UNSYNCHRONIZED标记未获得锁的线程. 一般只有两个线程争抢锁标记时,优先使用轻量级锁.

  3. 自旋锁
    自旋锁是一个过渡锁,是从偏向锁轻量级锁的过渡.
    若当前线程未能抢到锁,为提高效率,JVM自动执行若干次空循环,再次申请锁,而不是直接进入阻塞状态.

  4. 重量级锁
    重量级锁即为我们在上一节探讨的具有完整Monitor功能的锁.

Java中的各种锁对程序员来说是透明的: 在创建锁时,JVM先创建最轻的锁,若不满足条件则将锁逐次升级. 这四种锁之间只能升级,不能降级.

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值