并发编程11:Synchronized与锁升级

news2024/9/22 4:03:20

文章目录

  • 11.1 面试题
  • 11.2 Synchronized的性能变化
  • 11.3 Synchronized锁种类及升级步骤
    • 11.3.1 多线程访问情况
    • 11.3.2 升级流程
    • 11.3.3 无锁
    • 11.3.4 偏锁
    • 11.3.5 轻锁
    • 11.3.6 重锁
    • 11.3.7 小总结
  • 11.4 JIT编译器对锁的优化
    • 11.4.1 JIT
    • 11.4.2 锁消除
    • 11.4.3 锁粗化
  • 11.5 小总结

11.1 面试题

  • 谈谈你对Synchronized的理解
  • Sychronized的锁升级你聊聊
  • Synchronized实现原理,monitor对象什么时候生成的?知道monitor的monitorenter和monitorexit这两个是怎么保证同步的嘛?或者说这两个操作计算机底层是如何执行的
  • 偏向锁和轻量级锁有什么区别

11.2 Synchronized的性能变化

  • Java5以前,只有Synchronized,这个是操作系统级别的重量级操作

    • 重量级锁,假如锁的竞争比较激烈的话,性能下降
    • Java 5之前 用户态和内核态之间的转换
      在这里插入图片描述
  • Java6 之后为了减少获得锁和释放锁所带来的性能消耗,引入了轻量级锁和偏向锁

11.3 Synchronized锁种类及升级步骤

11.3.1 多线程访问情况

  • 只有一个线程来访问,有且唯一Only One
  • 有两个线程(2个线程交替访问)
  • 竞争激烈,更多线程来访问

11.3.2 升级流程

  • Synchronized用的锁是存在Java对象头里的MarkWord中,锁升级功能主要依赖MarkWord中锁标志位和释放偏向锁标志位
    在这里插入图片描述

  • 锁指向,请牢记

    • 偏向锁:MarkWord存储的是偏向的线程ID
    • 轻量锁:MarkWord存储的是指向线程栈中Lock Record的指针
    • 重量锁:MarkWord存储的是指向堆中的monitor对象(系统互斥量指针)

11.3.3 无锁

在这里插入图片描述

11.3.4 偏锁

偏向锁:单线程竞争,当线程A第一次竞争到锁时,通过修改MarkWord中的偏向线程ID、偏向模式。如果不存在其他线程竞争,那么持有偏向锁的线程将永远不需要进行同步
主要作用:

  • 当一段同步代码一直被同一个线程多次访问,由于只有一个线程那么该线程在后续访问时便会自动获得锁
  • 同一个老顾客来访,直接老规矩行方便
    结论:
  • HotSpot的作者经过研究发现,大多数情况下:在多线程情况下,锁不仅不存在多线程竞争,还存在由同一个线程多次获得的情况,偏向锁就是在这种情况下出现的,它的出现是为了解决只有一个线程执行同步时提高性能
  • 偏向锁会偏向于第一个访问锁的线程,如果在接下来的运行过程中,该锁没有被其他线程访问,则持有偏向锁的线程将永远不需要出发同步。也即偏向锁在资源在没有竞争情况下消除了同步语句,懒得连CAS操作都不做了,直接提高程序性能。
    理论落地:
    在这里插入图片描述

技术实现:
在这里插入图片描述

偏向锁JVM命令:
在这里插入图片描述

案例演示:

  • 偏向锁默认情况演示—只有一个线程
public class SynchronizedUpDemo {

    public static void main(String[] args) {
        /**
         * 这里偏向锁在JDK6以上默认开启,开启后程序启动几秒后才会被激活,可以通过JVM参数来关闭延迟 -XX:BiasedLockingStartupDelay=0
         */
//        try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
        Object o = new Object();
        synchronized (o) {
            System.out.println(ClassLayout.parseInstance(o).toPrintable());
        }
    }
}

在这里插入图片描述

偏向锁的撤销:

  • 当有另外一个线程逐步来竞争锁的时候,就不能再使用偏向锁了,要升级为轻量级锁,使用的是等到竞争出现才释放锁的机制
  • 竞争线程尝试CAS更新对象头失败,会等到全局安全点此时不会执行任何代码)撤销偏向锁,同时检查持有偏向锁的线程是否还在执行:
    • 第一个线程正在执行Synchronized方法(处于同步块),它还没有执行完,其他线程来抢夺,该偏向锁会被取消掉并出现锁升级,此时轻量级锁由原来持有偏向锁的线程持有,继续执行同步代码块,而正在竞争的线程会自动进入自旋等待获得该轻量级锁
    • 第一个线程执行完Synchronized(退出同步块),则将对象头设置为无所状态并撤销偏向锁,重新偏向。
      在这里插入图片描述

题外话:Java15以后逐步废弃偏向锁,需要手动开启------->维护成本高

11.3.5 轻锁

概念:多线程竞争,但是任意时候最多只有一个线程竞争,即不存在锁竞争太激烈的情况,也就没有线程阻塞。
主要作用:有线程来参与锁的竞争,但是获取锁的冲突时间极短---------->本质是自旋锁CAS
在这里插入图片描述

轻量锁的获取:
在这里插入图片描述
在这里插入图片描述

案例演示:
在这里插入图片描述

自旋一定程度和次数(Java8 之后是自适应自旋锁------意味着自旋的次数不是固定不变的):

  • 线程如果自旋成功了,那下次自旋的最大次数会增加,因为JVM认为既然上次成功了,那么这一次也大概率会成功
  • 如果很少会自选成功,那么下次会减少自旋的次数甚至不自旋,避免CPU空转

轻量锁和偏向锁的区别:

  • 争夺轻量锁失败时,自旋尝试抢占锁
  • 轻量级锁每次退出同步块都需要释放锁,而偏向锁是在竞争发生时才释放锁

11.3.6 重锁

有大量线程参与锁的竞争,冲突性很高
在这里插入图片描述
在这里插入图片描述

11.3.7 小总结

  • 锁升级的过程
    在这里插入图片描述

  • 锁升级后,hashcode去哪儿了?
    在这里插入图片描述
    在这里插入图片描述

  • 各种锁优缺点、synchronized锁升级和实现原理
    在这里插入图片描述

11.4 JIT编译器对锁的优化

11.4.1 JIT

Just In Time Compiler 即时编译器

11.4.2 锁消除

/**
 * 锁消除
 * 从JIT角度看想相当于无视他,synchronized(o)不存在了
 * 这个锁对象并没有被共用扩散到其他线程使用
 * 极端的说就是根本没有加锁对象的底层机器码,消除了锁的使用
 */

public class LockClearUpDemo {
    static Object object = new Object();

    public void m1() {
        //锁消除问题,JIT会无视它,synchronized(o)每次new出来的,都不存在了,非正常的
        Object o = new Object();
        synchronized (o) {
            System.out.println("-----------hello LockClearUpDemo" + "\t" + o.hashCode() + "\t" + object.hashCode());
        }
    }

    public static void main(String[] args) {
        LockClearUpDemo lockClearUpDemo = new LockClearUpDemo();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                lockClearUpDemo.m1();
            }, String.valueOf(i)).start();
        }
    }
}
/**
 * -----------hello LockClearUpDemo	229465744	57319765
 * -----------hello LockClearUpDemo	219013680	57319765
 * -----------hello LockClearUpDemo	1109337020	57319765
 * -----------hello LockClearUpDemo	94808467	57319765
 * -----------hello LockClearUpDemo	973369600	57319765
 * -----------hello LockClearUpDemo	64667370	57319765
 * -----------hello LockClearUpDemo	1201983305	57319765
 * -----------hello LockClearUpDemo	573110659	57319765
 * -----------hello LockClearUpDemo	1863380256	57319765
 * -----------hello LockClearUpDemo	1119787251	57319765
 */

11.4.3 锁粗化

/**
 * 锁粗化
 * 假如方法中首尾相接,前后相邻的都是同一个锁对象,那JIT编译器会把这几个synchronized块合并为一个大块
 * 加粗加大范围,一次申请锁使用即可,避免次次的申请和释放锁,提高了性能
 */
public class LockBigDemo {
    static Object objectLock = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (objectLock) {
                System.out.println("111111111111");
            }
            synchronized (objectLock) {
                System.out.println("222222222222");
            }
            synchronized (objectLock) {
                System.out.println("333333333333");
            }
            synchronized (objectLock) {
                System.out.println("444444444444");
            }
            //底层JIT的锁粗化优化
            synchronized (objectLock) {
                System.out.println("111111111111");
                System.out.println("222222222222");
                System.out.println("333333333333");
                System.out.println("444444444444");
            }
        }, "t1").start();
    }
}

11.5 小总结

没有锁:自由自在
偏向锁:一个线程
轻量锁:两个线程,CAS
重量锁:多个线程,阻塞

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/511368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电影《银河护卫队3》观后感

上周看了电影《银河护卫队3》&#xff0c;本部电影&#xff0c;主要是围绕着主角团队中的一个队员展开叙事的&#xff0c;在团队中&#xff0c;这名队员叫“火箭”&#xff0c;是一只经过基因改造过的浣熊。 当初进行改造的团队&#xff0c;是一家拥有基因改造技术的团队&…

基于SpringBoot, Vue实现的校园二手书交易系统

背景 在Internet高速发展的今天&#xff0c;计算机的应用几乎完全覆盖我们生活的各个领域&#xff0c;互联网在经济&#xff0c;生活等方面有着举足轻重的地位&#xff0c;成为人们资源共享&#xff0c;信息快速传递的重要渠道。在中国&#xff0c;网上管理的兴起也同时飞速发…

Solidity中哈希函数的编码与解码

起因 写这篇文章的起因&#xff0c;是我在前端调试合约的时候&#xff0c;发现合约报错了&#xff0c;点开命令行报错&#xff0c;发现返回的是合约的 callData&#xff0c;我直接表演一个眼前一黑&#xff0c;我怎么直接的知道是调用哪个方法的时候报错呢&#xff1f; 于是有…

【网络基础知识概念】路由器,交换机,无线AP,DHCP,DNS,WAN接口和LAN接口是什么?(附实物图详解)

【写在前面】其实在做一些试题的时候&#xff0c;经常会有些概念性的东西完全不清楚&#xff0c;今天我就带大家整理一下&#xff0c;交换机是啥&#xff1f;路由器是啥&#xff1f;无线AP是啥&#xff1f;ADSL又是什么&#xff0c;啥叫DHCP&#xff0c;DNS又是啥&#xff1f;W…

改进YOLOv5 | C3模块改动篇 | 轻量化设计 |骨干引入动态卷积|CondConv

CondConv: Conditionally Parameterized Convolutions for Efficient Inference 卷积是当前CNN网络的基本构成单元之一,它的一个基本假设是:卷积参数对所有样例共享。作者提出一种条件参数卷积,它可以为每个样例学习一个特定的卷积核参数,通过替换标准卷积,CondConv可以提…

shell脚本之“sort“、“uniq“、“tr“、“cut“命令详解

文章目录 sort命令uniq命令tr命令cut命令 sort命令 以行为单位对文件内容进行排序&#xff0c;也可以根据不同的数据类型来排序. 比较原则&#xff1a;从首字符向后&#xff0c;依次按ASCII码值进行比较&#xff0c;最后将他们按升序输出. 语法格式 sort [选项] 参数 cat …

c++ this指针

this指针介绍&#xff1a; c中成员变量和成员函数分开存储&#xff0c;每一个非静态成员函数只会有一个实例&#xff0c;多个同类型对象共用这一个成员函数。那么代码怎么区分哪个对象调用自己呢&#xff1f;this指针由此应运而生。 c通过提供对象指针&#xff0c;this指针。…

2020年下半年软件设计师下午试题

【试题四】希尔排序 【说明】 希尔排序算法又称最小增量排序算法&#xff0c;其基本思想是&#xff1a; 步骤1 :构造一个步长序列delta、deltak、 deltak &#xff0c;其中delta1n/2 &#xff0c;后面的每个delta是前一个的1/2 &#xff0c; deltak1&#xff1b; 步骤2 :根…

【shell脚本里的命令】

目录 一、sort命令1.1、命令演示 二、unip命令1、命令演示1、列题:2、使用脚本来查看用户有没有被恶意登录&#xff0c;查看登录用户的对应ip地址 三、tr命令1.1、命令演示1.2、使用tr命令对数组进行排序 五、从Windows里拉文件到Linux系统中要做的潜在条件六、cut命令 一、sor…

vue 阻止事件冒泡和捕获

文章目录 1. js 事件的三阶段2. js 阻止事件冒泡&#xff0c;捕获3、JavaScript基础知识&#xff1a;preventDefault和stopPropagationpreventDefault()事件方法stopPropagation()事件方法 click.stop : 阻止事件冒泡 click.prevent : 阻止事件默认行为 click.self : 事件只作用…

卡尔曼滤波器-公式推导 | 原理分析 | 将卡尔曼滤波器在MatLab中简单实现

目录 1.状态转移2.协方差矩阵3.噪声协方差矩阵的传递4.观测矩阵5.状态更新6.噪声协方差矩阵的更新7.在MatLab中实现卡尔曼滤波器1.状态转移 卡尔曼滤波器又称为最佳线性滤波器。优点有实现简单、纯时域滤波器、不需要进行频域变换等。 假设有一辆汽车在路上行驶,用位置和速度…

《学会提问》读后感

文章目录 批判性思维是什么&#xff1f;《学会提问》讲了什么&#xff1f;怎么成为一个批判性思维者&#xff1f; 批判性思维是什么&#xff1f; ​ 批判性思维是什么&#xff1f;在接触之前我是没有概念的&#xff0c;先借用百度百科一句话&#xff1a;批判性思维&#xff08…

Android 引入hunter-timing监测UI主线程函数运行时耗时,Java(2)

Android 引入hunter-timing监测UI主线程函数运行时耗时&#xff0c;Java&#xff08;2&#xff09; &#xff08;1&#xff09;在工程的根build.gradle文件配置&#xff1a; buildscript {repositories {mavenCentral()}dependencies {classpath cn.quinnchen.hunter:hunter-t…

c语言实现三子棋(思路+项目展示+源代码)

&#x1f4d5;博主介绍&#xff1a;目前大一正在学习c语言&#xff0c;数据结构&#xff0c;计算机网络。 c语言学习&#xff0c;是为了更好的学习其他的编程语言&#xff0c;C语言是母体语言&#xff0c;是人机交互接近底层的桥梁。 本章来写一个三子棋小游戏吧。 让我们开启c…

java版本微信机器人使用教程V1.0

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号雄雄的小课堂 现在是&#xff1a;2023年5月10日17:57:02 前言 历经好多天&#xff0c;java版本的微信机器人终于写完了初版了&#xff0c;接下来开放注册&#xff0c;大家先试用一下&#xff0c;有问题可以提出来&a…

配置Windows终端直接执行Python脚本,无需输入“python“

配置Windows终端直接执行Python脚本&#xff0c;无需输入"python" 1. 将Python加入环境变量2. 将Python后缀加入环境变量PATHEXT中3. 修改Python脚本的默认打开方式4. *将Python脚本命令加入环境变量*5. 测试 在Linux系统中&#xff0c;在Python脚本的开头指定Python…

Java基础(二十二):File类与IO流

Java基础系列文章 Java基础(一)&#xff1a;语言概述 Java基础(二)&#xff1a;原码、反码、补码及进制之间的运算 Java基础(三)&#xff1a;数据类型与进制 Java基础(四)&#xff1a;逻辑运算符和位运算符 Java基础(五)&#xff1a;流程控制语句 Java基础(六)&#xff1…

MySQL的内,外,自连接复习

目录 1.找出每个员工的薪资等级&#xff0c;要求显示员工名&#xff0c;薪资&#xff0c;薪资等级 2.查询员工的上级领导&#xff0c;要求显示员工名和对应的领导名 外连接的引入 五月 1.找出每个员工的薪资等级&#xff0c;要求显示员工名&#xff0c;薪资&#xff0c;薪资等…

【笔试强训选择题】Day10.习题(错题)解析

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;笔试强训选择题 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01; 文章目录…

Vue电商项目--开发ListContainer模块

swiper基本使用 上节&#xff0c;我们使用了mock把数据成功的存储到了banner组件当中。现在先复习一下swiper这个轮播图插件的使用 Swiper中文网-轮播图幻灯片js插件,H5页面前端开发 下载swiper 首先我们需要css和js。然后把这俩个捞走 看说明书&#xff0c;引入js和css 这里…