栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java悲观锁机制

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java悲观锁机制

1.什么是锁:在多线程并发的环境下,对同一个资源进行争抢时,可能会出现线程不安全的情况,通过锁来对资源进行锁定,当一个线程持有锁时,其他线程必须等待,其实这是失去了多线程的意义,变成了串行化。

2.锁是一种抽象概念,在Java中采用了两种实现方式 :

  1) 基于对象的悲观锁    :    在Java中,每个对象都有一把锁,这把锁存放在对象头中,记录了当前对象被哪个对象占用。

   2)基于CAS的乐观锁

3. 对象,对象头结构

1)对象:分为 对象头,实例数据(初始化对象时设定的属性和状态等内容),对齐填充字节(是为了满足Java对象大小是8字节的倍数而设计的)

2)对象头: (32位系统,8字节,64bit)

      Class Pointer 一个指针,指向当前对象类型所在方法区的Class信息

       MarkWord(32bit)   存储了许多当前对象的运行时的状态信息。如HashCode,锁状态标志,指向锁记录的指针,偏向线程ID,锁标志位等。

这把抽象的锁的信息存储在对象头的MarkWord中

4.锁的四种状态:

无锁 ,偏向锁,轻量级锁,重量级锁

5.synchronized关键字

在Java中,启用悲观锁(对象锁)是利用synchronized关键字。

synchronized被编译后会生成monitorenter和monitorexit两个字节码指令,依赖这两个字节码指令来进行线程同步

6. Monitor 监视器(一个只能容纳一个人的房间)

 这就是synchronized的同步机制(通过Monitor来对线程进行控制),但是性能大大下降,由于monitor的下层时依赖于操作系统的Mutex Lock 来实现的。Java线程本质上是对操作系统线程的映射,每当挂起或者唤醒一个线程都要切换到操作系统的内核态,这个操作是比较重量级的,有的时候,切换时间超过了执行任务时间。

7.对synchronized(重量级锁)进行优化 : 偏向锁,轻量级锁 

8.对象锁的四种状态

1)无锁

没有对资源进行操作系统级别(Mutex Lock)的锁定

两种语义:(1)没有多线程,没有共享对象,也没有修改数据。(2)资源会被竞争,但是不会使用操作系统同步原语进行资源锁定,而是通过别的机制来控制同步。比如CAS,通过这种函数级别的锁,我们可进行无锁编程。虽然无锁效率高,但是并不意味着无锁可以替代有锁。

2)偏向锁

偏向即为偏爱。假如只有一个线程,那么最为理想,不需要通过操作系统进行状态切换,只在用户态就可以把这件事做完。我们设想,这个对象的锁可以认识这个线程,只要它来,就把锁交出去,即这把锁偏爱这个线程,即偏向锁。

偏向锁的具体实现:

 从后往前先判断锁的状态,在去读MarkWord的前23个bit,即线程ID。

3)轻量级锁

当对象发现不止有一个线程,有多个线程在竞争锁,那么偏向锁会升级为轻量级锁。

其标志为会变为00.

轻量级锁如何判断线程和锁之间的绑定关系呢?

MarkWord前30个bit变为了指向虚拟机栈中锁记录的指针。

当一个线程想要得到这个对象的锁时,假如看到MarkWord的标志为为00,就知道了它是一个轻量级锁,这时这个线程会在自己的虚拟机栈中开辟一块称为 Lock Record 的空间。

那么Lock Record 中存放什么呢?对象头的MarkWord副本和Owner指针。

线程通过CAS尝试去获取锁,一旦获得那么就复制该对象的MarkWord到自己的虚拟机栈中的Lock Record中,并且将LockRecord中的Owner指针指向该对象锁,同时MarkWord的前30个bit将生成指向持有该对象锁的线程虚拟机栈中的Lock Record ,这样一来就形成了线程和对象锁的绑定。彼此知道互相的存在。

此时,拿到锁的线程可以去干活了,这时如果有其它线程也要得到这把锁,其它线程将会“自旋”。

自旋:可以理解为一种轮询,想要获得锁的线程不断地尝试去看一下锁有没有被释放,如果释放了,就获取。如果没有释放就进行下一次循环。这种方式和被操作系统挂起堵塞不同,如果锁很快被释放了,那么这种通过自旋去获取锁的方式效率很高,完全是在用户空间上解决,不需要进行系统中断和现场恢复。

自旋相当于CPU在空转,如果时间过长,将会造成CPU资源浪费。于是有一种“适应性自旋”的优化。就是说自旋的时间动态调整。由上一次在同一个锁上的自旋时间及锁的状态来决定,比如在同一个锁上,当前正在自旋等待的线程刚刚成功获得过锁,但是锁被其他线程持有,那么虚拟机就会认为下次自旋很有可能再次成功,进而它将允许更长的自旋时间,反之亦然。这就是“适应性自旋”。

4)重量级锁

假如一个对象锁被一个线程持有,同时也有多个线程正在自旋等待,即一旦自旋等待的线程数超过一定的数量,轻量级锁升级为重量级锁。

如果对象锁被标记为重量级锁,那么和上文相同,用过Monitor来对线程进行控制,此时将会使用同步原语来锁定资源,对线程的控制也最为严格。

轻量级锁和重量级锁的区别:

轻量级锁等待的线程是在自旋,重量级锁等待的线程在等待队列中。

各有利弊,自旋时间过长,消耗资源过多,浪费CPU资源。不如直接进入队列列。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1007665.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号