返回顶部
首页 > 资讯 > 前端开发 > JavaScript >web开发锁的状态以及升级方法有哪些
  • 683
分享到

web开发锁的状态以及升级方法有哪些

2024-04-02 19:04:59 683人浏览 薄情痞子
摘要

锁的状态以及升级方法有哪些,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、前言锁的状态总共有四种,级别由低到高

的状态以及升级方法有哪些,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

web开发锁的状态以及升级方法有哪些

一、前言

锁的状态总共有四种,级别由低到高依次为:无锁、偏向锁、轻量级锁、重量级锁,这四种锁状态分别代表什么,为什么会有锁升级?其实在 jdk  1.6之前,synchronized 还是一个重量级锁,是一个效率比较低下的锁,但是在JDK  1.6后,JVM为了提高锁的获取与释放效率对(synchronized )进行了优化,引入了 偏向锁 和 轻量级锁  ,从此以后锁的状态就有了四种(无锁、偏向锁、轻量级锁、重量级锁),并且四种状态会随着竞争的情况逐渐升级,而且是不可逆的过程,即不可降级,也就是说只能进行锁升级(从低级别到高级别),不能锁降级(高级别到低级别),意味着偏向锁升级成轻量级锁后不能降级成偏向锁。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率。

二、锁的四种状态

在 synchronized 最初的实现方式是  “阻塞或唤醒一个Java线程需要操作系统切换CPU状态来完成,这种状态切换需要耗费处理器时间,如果同步代码块中内容过于简单,这种切换的时间可能比用户代码执行的时间还长”,这种方式就是  synchronized实现同步最初的方式,这也是当初开发者诟病的地方,这也是在JDK6以前  synchronized效率低下的原因,JDK6中为了减少获得锁和释放锁带来的性能消耗,引入了“偏向锁”和“轻量级锁”。

所以目前锁状态一种有四种,从级别由低到高依次是:无锁、偏向锁,轻量级锁,重量级锁,锁状态只能升级,不能降级

如图所示:

web开发锁的状态以及升级方法有哪些

三、锁状态的思路以及特点

web开发锁的状态以及升级方法有哪些

四、锁对比

web开发锁的状态以及升级方法有哪些

五、Synchronized锁

synchronized 用的锁是存在Java对象头里的,那么什么是对象头呢?

5.1 Java 对象头

我们以 Hotspot 虚拟机为例,Hopspot 对象头主要包括两部分数据:MarkWord(标记字段)和KlassPointer(类型指针)

Mark  Word:默认存储对象的HashCode,分代年龄和锁标志位信息。这些信息都是与对象自身定义无关的数据,所以Mark  Word被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据。它会根据对象的状态复用自己的存储空间,也就是说在运行期间Mark  Word里存储的数据会随着锁标志位的变化而变化。

Klass Point:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

在上面中我们知道了, synchronized 用的锁是存在Java对象头里的,那么具体是存在对象头哪里呢?答案是:存在锁对象的对象头的Mark  Word中,那么MarkWord在对象头中到底长什么样,它到底存储了什么呢?

在64位的虚拟机中:

web开发锁的状态以及升级方法有哪些

在32位的虚拟机中:

 web开发锁的状态以及升级方法有哪些

下面我们以 32位虚拟机为例,来看一下其 Mark Word 的字节具体是如何分配的

无锁:对象头开辟 25bit 的空间用来存储对象的 hashcode ,4bit 用于存放对象分代年龄,1bit 用来存放是否偏向锁的标识位,2bit  用来存放锁标识位为01

偏向锁: 在偏向锁中划分更细,还是开辟 25bit 的空间,其中23bit 用来存放线程ID,2bit 用来存放 Epoch,4bit  存放对象分代年龄,1bit 存放是否偏向锁标识, 0表示无锁,1表示偏向锁,锁的标识位还是01

轻量级锁:在轻量级锁中直接开辟 30bit 的空间存放指向栈中锁记录的指针,2bit 存放锁的标志位,其标志位为00

重量级锁: 在重量级锁中和轻量级锁一样,30bit 的空间用来存放指向重量级锁的指针,2bit 存放锁的标识位,为11

GC标记: 开辟30bit 的内存空间却没有占用,2bit 空间存放锁标志位为11。

其中无锁和偏向锁的锁标志位都是01,只是在前面的1bit区分了这是无锁状态还是偏向锁状态

关于内存的分配,我们可以在git中openJDK中 markOop.hpp 可以看出:

public:   // Constants   enum { age_bits                 = 4,          lock_bits                = 2,          biased_lock_bits         = 1,          max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,          hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,          cms_bits                 = LP64_ONLY(1) NOT_LP64(0),          epoch_bits               = 2   };
  • age_bits: 就是我们说的分代回收的标识,占用4字节

  • lock_bits: 是锁的标志位,占用2个字节

  • biasedlockbits: 是是否偏向锁的标识,占用1个字节

  • maxhashbits: 是针对无锁计算的hashcode 占用字节数量,如果是32位虚拟机,就是 32 - 4 - 2 -1 = 25  byte,如果是64 位虚拟机,64 - 4 - 2 - 1 = 57 byte,但是会有 25 字节未使用,所以64位的 hashcode 占用 31  byte

  • hash_bits: 是针对 64 位虚拟机来说,如果最大字节数大于 31,则取31,否则取真实的字节数

  • cms_bits: 不是64位虚拟机就占用 0 byte,是64位就占用 1byte

  • epoch_bits: 就是 epoch 所占用的字节大小,2字节。

5.2 Monitor

Monitor 可以理解为一个同步工具或一种同步机制,通常被描述为一个对象。每一个 Java 对象就有一把看不见的锁,称为内部锁或者 Monitor  锁。

Monitor 是线程私有的数据结构,每一个线程都有一个可用 monitor record 列表,同时还有一个全局的可用列表。每一个被锁住的对象都会和一个  monitor 关联,同时 monitor 中有一个 Owner 字段存放拥有该锁的线程的唯一标识,表示该锁被这个线程占用。

Synchronized是通过对象内部的一个叫做监视器锁(monitor)来实现的,监视器锁本质又是依赖于底层的操作系统的 Mutex  Lock(互斥锁)来实现的。而操作系统实现线程之间的切换需要从用户态转换到核心态,这个成本非常高,状态之间的转换需要相对比较长的时间,这就是为什么  Synchronized 效率低的原因。因此,这种依赖于操作系统 Mutex Lock 所实现的锁我们称之为重量级锁。

随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级的重量级锁(但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级)。JDK  1.6中默认是开启偏向锁和轻量级锁的,我们也可以通过-XX:-UseBiasedLocking=false来禁用偏向锁。

六、锁的分类

6.2 无锁

无锁是指没有对资源进行锁定,所有的线程都能访问并修改同一个资源,但同时只有一个线程能修改成功。

无锁的特点是修改操作会在循环内进行,线程会不断的尝试修改共享资源。如果没有冲突就修改成功并退出,否则就会继续循环尝试。如果有多个线程修改同一个值,必定会有一个线程能修改成功,而其他修改失败的线程会不断重试直到修改成功。

6.3 偏向锁

初次执行到synchronized代码块的时候,锁对象变成偏向锁(通过CAS修改对象头里的锁标志位),字面意思是“偏向于第一个获得它的线程”的锁。执行完同步代码块后,线程并不会主动释放偏向锁。当第二次到达同步代码块时,线程会判断此时持有锁的线程是否就是自己(持有锁的线程ID也在对象头里),如果是则正常往下执行。由于之前没有释放锁,这里也就不需要重新加锁。如果自始至终使用锁的线程只有一个,很明显偏向锁几乎没有额外开销,性能极高。

偏向锁是指当一段同步代码一直被同一个线程所访问时,即不存在多个线程的竞争时,那么该线程在后续访问时便会自动获得锁,从而降低获取锁带来的消耗,即提高性能。

当一个线程访问同步代码块并获取锁时,会在 Mark Word 里存储锁偏向的线程 ID。在线程进入和退出同步块时不再通过 CAS  操作来加锁和解锁,而是检测 Mark Word 里是否存储着指向当前线程的偏向锁。轻量级锁的获取及释放依赖多次 CAS 原子指令,而偏向锁只需要在置换  ThreadID 的时候依赖一次 CAS 原子指令即可。

偏向锁只有遇到其他线程尝试竞争偏向锁时,持有偏向锁的线程才会释放锁,线程是不会主动释放偏向锁的。

关于偏向锁的撤销,需要等待全局安全点,即在某个时间点上没有字节码正在执行时,它会先暂停拥有偏向锁的线程,然后判断锁对象是否处于被锁定状态。如果线程不处于活动状态,则将对象头设置成无锁状态,并撤销偏向锁,恢复到无锁(标志位为01)或轻量级锁(标志位为00)的状态。

6.4 轻量级锁(自旋锁)

 web开发锁的状态以及升级方法有哪些

轻量级锁是指当锁是偏向锁的时候,却被另外的线程所访问,此时偏向锁就会升级为轻量级锁,其他线程会通过自旋(关于自旋的介绍见文末)的形式尝试获取锁,线程不会阻塞,从而提高性能。

轻量级锁的获取主要由两种情况:① 当关闭偏向锁功能时;② 由于多个线程竞争偏向锁导致偏向锁升级为轻量级锁。

一旦有第二个线程加入锁竞争,偏向锁就升级为轻量级锁(自旋锁)。这里要明确一下什么是锁竞争:如果多个线程轮流获取一个锁,但是每次获取锁的时候都很顺利,没有发生阻塞,那么就不存在锁竞争。只有当某线程尝试获取锁的时候,发现该锁已经被占用,只能等待其释放,这才发生了锁竞争。

在轻量级锁状态下继续锁竞争,没有抢到锁的线程将自旋,即不停地循环判断锁是否能够被成功获取。获取锁的操作,其实就是通过CAS修改对象头里的锁标志位。先比较当前锁标志位是否为“释放”,如果是则将其设置为“锁定”,比较并设置是原子性发生的。这就算抢到锁了,然后线程将当前锁的持有者信息修改为自己。

长时间的自旋操作是非常消耗资源的,一个线程持有锁,其他线程就只能在原地空耗CPU,执行不了任何有效的任务,这种现象叫做忙等(busy-waiting)。如果多个线程用一个锁,但是没有发生锁竞争,或者发生了很轻微的锁竞争,那么synchronized就用轻量级锁,允许短时间的忙等现象。这是一种折衷的想法,短时间的忙等,换取线程在用户态和内核态之间切换的开销。

6.4 重量级锁

重量级锁显然,此忙等是有限度的(有个计数器记录自旋次数,默认允许循环10次,可以通过虚拟机参数更改)。如果锁竞争情况严重,某个达到最大自旋次数的线程,会将轻量级锁升级为重量级锁(依然是CAS修改锁标志位,但不修改持有锁的线程ID)。当后续线程尝试获取锁时,发现被占用的锁是重量级锁,则直接将自己挂起(而不是忙等),等待将来被唤醒。

重量级锁是指当有一个线程获取锁之后,其余所有等待获取该锁的线程都会处于阻塞状态。

简言之,就是所有的控制权都交给了操作系统,由操作系统来负责线程间的调度和线程的状态变更。而这样会出现频繁地对线程运行状态的切换,线程的挂起和唤醒,从而消耗大量的系统资

看完上述内容,你们掌握锁的状态以及升级方法有哪些的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网JavaScript频道,感谢各位的阅读!

--结束END--

本文标题: web开发锁的状态以及升级方法有哪些

本文链接: https://lsjlt.com/news/80697.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • web开发锁的状态以及升级方法有哪些
    锁的状态以及升级方法有哪些,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、前言锁的状态总共有四种,级别由低到高...
    99+
    2024-04-02
  • Android开发升级AGP7.0后的适配方法有哪些
    本文小编为大家详细介绍“Android开发升级AGP7.0后的适配方法有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“Android开发升级AGP7.0后的适配方法有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习...
    99+
    2023-07-02
  • nodejs升级的方法有哪些
    这篇文章主要介绍“nodejs升级的方法有哪些”,在日常操作中,相信很多人在nodejs升级的方法有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”nodejs升级的方法有...
    99+
    2024-04-02
  • web开发中可以实现前端动画的方法有哪些
    这篇文章主要介绍web开发中可以实现前端动画的方法有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!   1、javascript直接实现   主要思想是通过setInterv...
    99+
    2024-04-02
  • 提升Web开发性能的技巧有哪些
    本篇内容介绍了“提升Web开发性能的技巧有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、采用反向代...
    99+
    2024-04-02
  • 查看mysql状态的方法有哪些
    有以下几种方法可以查看MySQL的状态:1. 使用命令行工具:可以通过在命令行中执行`mysqladmin status`命令来查看...
    99+
    2023-10-11
    mysql
  • k8s v1.5 web界面中kubernetes-dashboardv1.5的升级以及使用方法
    k8s v1.5 web界面中kubernetes-dashboardv1.5的升级以及使用方法,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。kubernetes d...
    99+
    2023-06-19
  • 在React中跨组件分发状态的方法有哪些
    小编给大家分享一下在React中跨组件分发状态的方法有哪些,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!问题;为了向您展示我的意思,我将使用一个简单的书籍CRUD(译者注:增加(Creat...
    99+
    2024-04-02
  • 升级Ubuntu 11.04 Natty的方法有哪些
    这篇文章主要讲解了“升级Ubuntu 11.04 Natty的方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“升级Ubuntu 11.04 Natty的方法有哪些”吧!在线升级: G...
    99+
    2023-06-16
  • 免费升级win11的方法有哪些
    今天小编给大家分享一下免费升级win11的方法有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。方法一:win11推送升级...
    99+
    2023-07-02
  • web开发中清除浮动的方法有哪些
    这篇文章给大家分享的是有关web开发中清除浮动的方法有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。html    <div&g...
    99+
    2024-04-02
  • Web开发中盒子居中方法有哪些
    本篇内容介绍了“Web开发中盒子居中方法有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、记录下几种盒子居中的方法: 1.0...
    99+
    2023-06-08
  • Web Services使用多态的方法有哪些
    小编给大家分享一下Web Services使用多态的方法有哪些,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!在Web Services方法中,往往使用的都是一个具体类型的参数,这个参数一般就是一个数据对象。ASP.NET ...
    99+
    2023-06-17
  • 提升web前端开发效率的工具有哪些
    本篇内容介绍了“提升web前端开发效率的工具有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1. En...
    99+
    2024-04-02
  • 优秀Web开发者提升开发能力必知的事有哪些
    这篇文章主要介绍了优秀Web开发者提升开发能力必知的事有哪些,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。  1. 不要只盯着代码  如今人人都会写代码。很多业余爱好者也可以...
    99+
    2023-06-08
  • Flutter组件状态管理的方法有哪些
    这篇文章主要为大家展示了“Flutter组件状态管理的方法有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Flutter组件状态管理的方法有哪些”这篇文章吧。前言前面讲了Flutter布局,...
    99+
    2023-06-29
  • web开发中做外链的常用方法有哪些
    web开发中做外链的常用方法有哪些,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。“内容为王,外链为皇”的说法,说明了外链的重要性。做外链的方法...
    99+
    2024-04-02
  • web开发中队列的写法有哪些
    队列写法有哪些,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前言栈和队列是一对好兄弟,前面我们介...
    99+
    2024-04-02
  • web开发中页面内锚点定位及跳转方法有哪些
    这篇文章将为大家详细讲解有关web开发中页面内锚点定位及跳转方法有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。最简单的方法是锚点用<a>标签,在href...
    99+
    2024-04-02
  • Linux及Arm-Linux程序开发的方法有哪些
    本篇内容主要讲解“Linux及Arm-Linux程序开发的方法有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linux及Arm-Linux程序开发的方法有哪些”吧!一、Arm-Linux程...
    99+
    2023-06-09
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作