synchronized锁升级过程-程序员宅基地

技术标签: Java  java  

一.锁升级理论.

在synchronized锁升级过程中涉及到以下几种锁.先说一下这几种锁是什么意思.

偏向锁:只有一个线程争抢锁资源的时候.将线程拥有者标识为当前线程.
轻量级锁(自旋锁):一个或多个线程通过CAS去争抢锁,如果抢不到则一直自旋.
重量级锁:多个线程争抢锁,向内核申请锁资源,将未争抢成功的锁放到队列中直接阻塞.

为什么要有锁的升级过程?
      在最开始的时候,其实就是无锁直接到重量级锁,但是重量级锁需要向内核申请额外的锁资源,这就涉及到用户态和内核态的转换,比较浪费资源,而且大多数情况下,其实还是一个线程去争抢锁,完全不需要重量级锁.

锁的具体升级过程(通常情况下):

  1. 当只有一个线程去争抢锁的时候,会先使用偏向锁,就是给一个标识,说明现在这个锁被线程a占有.
  2. 后来又来了线程b,线程c,说凭什么你占有锁,需要公平的竞争,于是将标识去掉,也就是撤销偏向锁,升级为轻量级锁,三个线程通过CAS进行锁的争抢(其实这个抢锁过程还是偏向于原来的持有偏向锁的线程).
  3. 现在线程a占有了锁,线程b,线程c一直在循环尝试获取锁,后来又来了十个线程,一直在自旋,那这样等着也是干耗费CPU资源,所以就将锁升级为重量级锁,向内核申请资源,直接将等待的线程进行阻塞.

锁升级的过程如下所示:

在这里插入图片描述

什么情况下偏向锁才会升级为轻量级锁,什么时候轻量级锁才会升级为重量级锁?

  1. 只有一个线程的时候就是偏向锁(当偏向锁开启的时候,偏向锁默认开启),当争抢的线程超过一个,升级为轻量级锁.
  2. 当自旋的线程循环超过10次,或者线程等待的数量超过cpu的1/2,升级为重量级锁.其实轻量级锁就适用于那种执行任务很短的线程,可能通过一两次自旋,就能够获取到锁.

开启偏向锁一定比轻量级锁高效吗?
      不一定,比如在一开始已经知道某个资源就需要被多个线程争抢,此时就不需要开启偏向锁,因为偏向锁给了标识之后,还需要取消这个标识,重新抢锁,比如在JVM中,偏向锁默认是延迟4秒才开始的,因为JVM在启动的时候需要多个线程竞争资源,并且这个都是一开始知道的.

二.对象在内存中的内存布局

在堆中,一个对象会包含以下四个部分:
在这里插入图片描述

我们如果使用synchronized对某个对象进行加锁,就会体现在mark word区域.在最低两个字节加以标识.

如下如所示:
重量级锁 对应 10
轻量级锁 对应 00
无锁和偏向锁都对应01,这个时候需要倒数第三个字节加以区分,
即 无锁 对应 001, 偏向锁 对应 101

在这里插入图片描述

三.实操,用代码演示锁升级过程

在之前大概讲述了锁升级的过程和一些基础理论,现在用实际代码演示一下锁的升级过程.

1.首先这里引入一个api,通过这个可以显示出对象的内存的信息.
在这里插入图片描述
演示:
定义一个简单类,这个类有一个成员变量test.然后我们输出这个对象的内存信息.
在这里插入图片描述
输出信息如下:
在这里插入图片描述
2.使用程序演示锁升级过程
如下,给定一个锁对象,然后依次用一个线程,两个线程,多个线程去争抢锁,演示锁升级过程.

public class DemoApplication {
    
    static Object obj = new Object();
    //指定任务
     static class LockThread implements Runnable{
    
        @Override
        public void run() {
    
            synchronized (obj){
    
                //进行一些耗时操作
                String test="";
                for (int i = 0; i < 1000; i++) {
    
                    test += "2";
                }
            }
        }
    }
    public static void main(String[] args) {
    

        //只有一个线程去抢占锁
        new Thread(new LockThread()).start();
        System.out.println("===========偏向锁===========");
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());

        //两个线程抢占锁,升级为轻量级锁
        new Thread(new LockThread()).start();
        System.out.println("===========轻量级锁===========");
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());

        //多个线程抢占,一直在自旋,升级位重量级锁
        for (int i = 0; i < 20; i++) {
    
            new Thread(new LockThread()).start();
        }
        System.out.println("===========重量级锁===========");
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());

    }
}

输出结果如下,可以很直观的看到偏向锁–>轻量级锁–>重量级锁
在这里插入图片描述

其他注意点:
      并不是一定会有一个偏向锁->轻量级锁->重量级锁的过程,比如如果出现严重的耗时操作(sleep,或者wait等),就会直接由偏向锁升级为重量级锁.

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/wangliangluang/article/details/123463618

智能推荐

linux里面ping www.baidu.com ping不通的问题_linux桥接ping不通baidu-程序员宅基地

文章浏览阅读3.2w次,点赞16次,收藏90次。对于这个问题我也是从网上找了很久,终于解决了这个问题。首先遇到这个问题,应该确认虚拟机能不能正常的上网,就需要ping 网关,如果能ping通说明能正常上网,不过首先要用命令route -n来查看自己的网关,如下图:第一行就是默认网关。现在用命令ping 192.168.1.1来看一下结果:然后可以看一下电脑上面百度的ip是多少可以在linux里面ping 这个IP,结果如下:..._linux桥接ping不通baidu

android 横幅弹出权限,有关 android studio notification 横幅弹出的功能没有反应-程序员宅基地

文章浏览阅读512次。小妹在这里已经卡了2-3天了,研究了很多人的文章,除了低版本api 17有成功外,其他的不是channel null 就是没反应 (channel null已解决)拜托各位大大,帮小妹一下,以下是我的程式跟 gradle, 我在这里卡好久又没有人可问(哭)![image](/img/bVcL0Qo)public class MainActivity extends AppCompatActivit..._android 权限申请弹窗 横屏

CNN中padding参数分类_cnn “相同填充”(same padding)-程序员宅基地

文章浏览阅读1.4k次,点赞4次,收藏6次。valid padding(有效填充):完全不使用填充。half/same padding(半填充/相同填充):保证输入和输出的feature map尺寸相同。full padding(全填充):在卷积操作过程中,每个像素在每个方向上被访问的次数相同。arbitrary padding(任意填充):人为设定填充。..._cnn “相同填充”(same padding)

Maven的基础知识,java技术栈-程序员宅基地

文章浏览阅读790次,点赞29次,收藏28次。手绘了下图所示的kafka知识大纲流程图(xmind文件不能上传,导出图片展现),但都可提供源文件给每位爱学习的朋友一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长![外链图片转存中…(img-Qpoc4gOu-1712656009273)][外链图片转存中…(img-bSWbNeGN-1712656009274)]

getFullYear()和getYear()有什么区别_getyear和getfullyear-程序员宅基地

文章浏览阅读469次。Date对象取得年份有getYear和getFullYear两种方法经 测试var d=new Date;alert(d.getYear())在IE中返回 2009,在Firefox中会返回109。经查询手册,getYear在Firefox下返回的是距1900年1月1日的年份,这是一个过时而不被推荐的方法。而alert(d.getFullYear())在IE和FF中都会返回2009。因此,无论何时都应使用getFullYear来替代getYear方法。例如:2016年用 getFullYea_getyear和getfullyear

Unix传奇 (上篇)_unix传奇pdf-程序员宅基地

文章浏览阅读182次。Unix传奇(上篇) 陈皓 了解过去,我们才能知其然,更知所以然。总结过去,我们才会知道我们明天该如何去规划,该如何去走。在时间的滚轮中,许许多的东西就像流星一样一闪而逝,而有些东西却能经受着时间的考验散发着经久的魅力,让人津津乐道,流传至今。要知道明天怎么去选择,怎么去做,不是盲目地跟从今天各种各样琳琅满目前沿技术,而应该是去 —— 认认真真地了解和回顾历史。 Unix是目前还在存活的操作系_unix传奇pdf

随便推点

在VSCode中运行Jupyter Notebook_vscode jupyter notebook-程序员宅基地

文章浏览阅读7.8k次。在VSCode中运行Jupyter Notebook_vscode jupyter notebook

老赵书托(2):计算机程序的构造与解释-程序员宅基地

文章浏览阅读122次。我要推荐的第一本书便是大名鼎鼎的《Structure and Interpretation of Computer Programs》,在国内可以买到中译版,即机械工业出版社的《计算机程序的构造与解释》。 抽象豪不夸张地说,这是一本影响了好几代程序员的书。自从上世纪80年代MIT开始使用这本书作为教材开始,它使用Lisp语言——直到前两年才被Python取代,但是使用哪本教材不得而知,由这..._老赵书拖

图像处理之常见二值化方法汇总-程序员宅基地

文章浏览阅读6.1k次,点赞5次,收藏53次。图像处理之常见二值化方法汇总图像二值化是图像分析与处理中最常见最重要的处理手段,二值处理方法也非常多。越精准的方法计算量也越大。本文主要介绍四种常见的二值处理方法,通常情况下可以满足大多数图像处理的需要。主要本文讨论的方法仅针对RGB色彩空间。方法一:该方法非常简单,对RGB彩色图像灰度化以后,扫描图像的每个像素值,值小于127的将像素值设为0(黑色),值大于等于127..._web 图像二值画

基于springboot实现社区团购系统项目【项目源码+论文说明】计算机毕业设计-程序员宅基地

文章浏览阅读502次,点赞23次,收藏16次。在网站的整个开发过程中,首先对系统进行了需求分析,设计出系统的主要功能模块,其次对网站进行总体规划和详细设计,最后对基于Spring Boot的社区团购系统进行了系统测试,包括测试概述,测试方法,测试方案等,并对测试结果进行了分析和总结,进而得出系统的不足及需要改进的地方,为以后的系统维护和扩展提供了方便。现在的时代科技飞速地发展,网络交易已经深入大众的生活。项目开发的过程中,要按照规划、分期实施,特别是要注意在项目开发过程中要有条理,从点到面,一步步完善,不要贪图进度,要循环渐进的对项目进行开发。

ACwing 哈希算法入门:_ac算法 哈希-程序员宅基地

文章浏览阅读308次。哈希算法:将字符串映射为数字形式,十分巧妙,一般运用为进制数,进制据前人经验,一般为131,1331时重复率很低,由于字符串的数字和会很大,所以一般为了方便,一般定义为unsigned long long,爆掉时,即为对 2^64 取模,可以对于任意子序列的值进行映射为数字进而进行判断入门题目链接:AC代码:#include<bits/stdc++.h>using na..._ac算法 哈希

VS配置Qt和MySQL_在vs中 如何装qt5sqlmysql模块-程序员宅基地

文章浏览阅读952次,点赞13次,收藏27次。由于觉得Qt的编辑界面比较丑,所以想用vs2022的编辑器写Qt加MySQL的项目。_在vs中 如何装qt5sqlmysql模块

推荐文章

热门文章

相关标签