学习笔记9——JUC三种量级的锁机制

学习笔记系列开头惯例发布一些寻亲消息

链接:https://baobeihuijia.com/bbhj/contents/3/197325.html
在这里插入图片描述

  • 多线程访问共享资源冲突

    • 临界区:一段代码块存在对共享资源的多线程读写操作,称这段代码块为临界区

    • 竞态条件:多个线程在临界区内执行,由于代码的执行序列不同导致结果无法预测,称发生了竞态条件

  • 一些线程安全的例子(什么时候加锁什么时候不加):

    • 局部变量是线程安全的(每个线程创建的栈内部独立拥有)
      在这里插入图片描述

    • 局部变量引用的对象:如果用的对象的公共变量,需要加锁,因为对象在堆内
      在这里插入图片描述

    • 局部变量引用的对象:如果用的是对象方法内的局部变量**(虽然这种情况下每个线程在堆内单独拥有对象使用权,但是如果子类重写方法,新加了线程,那么也会出现两个线程共享局部变量的情况,所以尽量用final或者private将父类保护起来)**

    在这里插入图片描述

    • 线程安全类:

      • string:在定义string类的时候,就已经声明了final,所以不会出现子类继承string,并且修改string的读写逻辑为多线程,所以对于单独一个string来说,我们的读写是安全的,因为只有有一个线程进行读写,但是多个方法的组合之间可以插入不同的别的线程,所以不是原子或者说不是安全的。
        在这里插入图片描述
  • 在这里插入图片描述

  • 重量级锁——synchronized【父母考核:我听父母的,父母来决定我的owner,当追求者很多时,采用这种方案】

    • 加锁room,别的线程会进入block,直到本线程释放锁,才会唤醒别的block线程,在这个过程中就算时间片轮完该线程,其他线程也无法唤醒

    • 用对象锁的形式保证了临界区代码的原子性,避免多个线程一起执行同一段临界区代码,如果这个锁没有被用,那么就可以执行这段代码

    • 锁住对象和锁住类对象是不同的,并不互斥(也就是说,在执行锁住对象的时候,当这轮cpu片时间耗尽,cpu也会去执行锁住类对象的操作,类对象锁不会被阻塞)

      # 方法一
      synchronized(对象)
      
      # 方法二
      class Room {
          private int counter = 0;
          
      	// 等价于 synchronized(this)
          public synchronized void increment() {
              counter++;
          }
      
          public synchronized void decrement() {
              counter--;
          }
      
          public synchronized int getCounter() {
              return counter;
          }
      }
      
      # 方法三
      class Test{
      	// 等价于synchronized(Test.class)
      	public synchronized static void test(){
      	}
      }
      
    • Monitor

      • 对象头

        • 普通对象:32bit的Mark Word(25位hashcode,每个对象都有自己的哈希码,4位的GC分代,锁状态标志)+32bit的Klass Word(类型指针)
      • 数组对象:32bit mark word + 32bit klass word + 32bit的 数组长度

      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • synchronized的原理:

      • 每次线程遇到synchronized(obj),会去检查obj是否指向操作系统中的一个monitor,如果没有指向那就将obj对象的mask word 修改为monitor的地址,并将锁标志位从01改为10,将该线程置为monitor的Owner
      • 在此期间如果别的线程执行遇到synchronized(obj),那么就会索引到monitor,发现已经有别的owner,进入entrylist 变为BLOCKED状态
      • 当前owner执行完成后,随机唤醒一个BLOCKED线程,最后退出该对象时将自己的markword重置为hashcode等

      外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 重量级锁的线程自旋优化

      • 为了避免线程阻塞,发生上下文切换,从而自旋等待解锁
      • 适合多核cpu,单核的cpu没有自旋的意义,因为没有额外的cpu可以来执行自旋(需要等你结束我才能执行,但是我还总要中途打扰你问你好了没)
      • 自旋失败:几次自旋重试后还是得不到锁就进行阻塞
  • 轻量级锁(操作系统自动创建,不需要我们显式定义)【私定终生,我来决定我的owner】

    • 加锁:线程中创建一个LOCK RECORD 00表示轻量级锁,与对象头交换mask信息(类似于一种密码机制,只有当前线程完成后,才会把密码信息还给对象,别人来访问交换时这个对象已经是加锁状态)

    • 锁重入:当前线程已经拿到锁了,但是又执行了一遍synchronized(obj),这时会新建一个LOCK RECORD 00栈帧,数据这里会存储null,说明其他栈帧已经拿到锁了

    • 解锁:如果是null,直接清除即可,不是null则需要将mask word恢复给对象

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • 锁膨胀(追求者很多产生了竞争,发现决定权给到父母后,就需要与父母沟通)

      • 线程加轻量级锁失败,进入锁膨胀流程,变成重量级锁(修改原始密码为monitor地址,owner置为当前线程,后续线程进入阻塞)
      • 原来线程的轻量级锁解锁失败(因为密码匹配不对,对象的密码现在是monitor地址),需要进入重量级锁的解锁流程,即找到monitor对象,将owner置为null,并唤醒阻塞线程

    外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 偏向锁(只有一个线程一直重复用偏向——》有别的线程也来用该对象就会撤销变为轻量级锁——》锁之间有竞争交互就用重量级)

    • 原始:将对象的mask word与新建锁栈帧的头部信息交换(锁重入都会尝试交换信息,造成资源浪费)

    • 偏向:将对象的mask word修改为线程ID,锁重入就不会新建锁栈帧

    • 当前线程id释放后,线程id还是不会改变,该对象已经从属于该主线程

    • 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

    • ban掉偏向锁的方法

      • 当一个可偏向的对象调用了hashcode就会ban掉偏向锁
      • 当对象已经偏向一个线程了,另一个线程也来用该对象,但是不竞争,就会变为轻量级(线程id部分变为锁记录指针),如果竞争交互就是重量级
      • 调用wait,notify也会撤销,因为wait,notify只有重量级有
    • 批量重偏向

      • 超过一定阈值数量(20)的对象都在撤销偏向锁,就会认为偏向设置的线程有误,因此会将所有的对象偏向锁改为别的线程
      • 撤销的性能消耗比较大
      • 批量执行
    • 批量撤销

      • 撤销超过阈值(40)的对象都在撤销偏向锁换轻量级(说的是所有线程的总数),偏向就要求整个类原始对象和新对象不再偏向,直接轻量级
  • JIT即时编译进行逃逸分析

  • sleep和wait的区别(状态都是timewaiting)

    • sleep是线程的方法,执行时不会放弃锁:相当于屋子内的人把门锁死,直到醒来检查一下资源是否满足

    • wait是对象A的方法,会放弃锁,需要notify叫醒:屋子内的人发现缺资源就出来在门外等着A.wait(),等到资源满足执行notify【这种方法可以通过资源的识别需要通过while条件来判断】

      • synchronized(lock){
        	while(资源不满足){
        		lock.wait();
        	}
        	// 干活
        }
        
        synchronized(lock){
        	lock.notifyAll()
        }
        

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Anaconda文件目录(打开默认路径)更改

Anaconda 文件默认目录更改 每次打开 Anaconda 都在C盘怎么办,如何改为D盘或是其他盘符位置? 可以进行下述操作。 1. 单次修改路径 单次修改路径:在 exe 文件(Anaconda Prompt (Anaconda_py))中写入下面代码: jupyter notebook …

微信小程序ec-canvas(echarts)显示地图【以甘肃省为例】

文章目录 一、效果图二、实现1、下载echarts插件2、定制图形,生成 echarts.min.js 文件3、小程序中使用(1)下载甘肃地图(2)使用 参考文档《微信小程序使用echarts显示全国地图》《如何在微信小程序开发中使用echarts以…

详解Keras3.0 KerasCV API: StableDiffusion image-generation model

Stable Diffusion 图像生成模型,可用于根据简短的文本描述(称为“提示”)生成图片 keras_cv.models.StableDiffusion(img_height512, img_width512, jit_compileTrue) 参数说明 img_height:int,要生成的图像的高度…

安路IP核应用举例(OSC、UART)

1.OSC(内部振荡器) 按照Project->New Project顺序新建工程后,后按照Tools->IP Generator顺序,创建IP核,如下图: 安路FPGA的内置OSC振荡模块频率可选30MHz、60MHz。 可选Verilog或VHDL语言。 如图,生成的.v文件只…

美国 AGU 发布 AI 应用手册,明确 6 大指导方针

爆发性的 AI 应用:风险与机遇并存 在空间和环境科学领域,AI 工具的应用越来越广泛——诸如天气预报和气候模拟,能源及水资源管理等等。可以说,我们正在经历前所未有的 AI 应用爆发,面对其中的机遇与风险,更…

DTC 故障严重程度

文章目录 简介DTC严重性 位定义DTC 类别定义参考 简介 DTCSeverityMask(DTC严重性掩码)/ DTCSeverity(DTC严重性)包含了DTC严重性和DTC类别信息。 DTCSeverityMask(DTC严重性掩码)/DTCSeverit…

找不到mfc100u.dll,程序无法继续执行?三步即可搞定

在使用电脑过程中,我们经常会遇到一些错误提示,其中之一就是“找不到mfc100u.dll”。mfc100u.dll是Microsoft Foundation Class(MFC)库中的一个版本特定的DLL文件。MFC是微软公司为简化Windows应用程序开发而提供的一套C类库。它包…

接口测试工具Postman接口测试图文教程

一、前言 在前后端分离开发时,后端工作人员完成系统接口开发后,需要与前端人员对接,测试调试接口,验证接口的正确性可用性。而这要求前端开发进度和后端进度保持基本一致,任何一方的进度跟不上,都无法及时…

牛客网BC107矩阵转置

答案&#xff1a; #include <stdio.h> int main() {int n0, m0,i0,j0,a0,b0;int arr1[10][10]{0},arr2[10][10]{0}; //第一个数组用来储存原矩阵&#xff0c;第二个数组用来储存转置矩阵scanf("%d%d",&n,&m); if((n>1&&n<10)&&am…

【最新版】PyCharm基础调试功能详解

文章目录 一、断点1. 断点的类型a. 行断点b. 异常断点 2. 设置断点a. 设置行断点b. 设置异常断点 3. 管理断点a. 删除断点b. 将断点静音 二、调试功能0. 测试代码1. 设置断点2. 调试的多种启动方式3. 观察调试控制台a. 步过b. 步入c. 单步执行代码d. 步出e. 运行到光标处f. 重新…

vivado约束方法6

生成的时钟 定时约束向导建议在的输出上创建一个生成的时钟顺序单元&#xff0c;当它直接或通过驱动其他顺序单元的时钟引脚时一些互连逻辑。与PLL或MMCM不同&#xff0c;用户逻辑不能将主时钟&#xff0c;因此向导仅提供指定除法系数的选项&#xff0c;如中所示如下图所示&am…

protobuf基础学习

部分内容出自&#xff1a;https://blog.csdn.net/baidu_32237719/article/details/99723353 proto文件来预先定义的消息格式。数据包是按照proto文件所定义的消息格式完成二进制码流的编码和解码。proto文件&#xff0c;简单地说&#xff0c;就是一个消息的协议文件&#xff0c…

Cloudflare始终使用HTTPS且带参数跳转到www的域名

文章目录 设置教程设置图跳转实测 设置教程 关闭 SSL/TLS -> 边缘证书 的 Always Use HTTPS 规则 -> 页面规则 -> URL: http://www.example.com/* 设置成始终使用HTTPS 规则 -> 页面规则 -> URL: example.com/* 设置成 转发URL301重定向到 to https://www.ex…

sql 数据类型注入+tamper

数字型 0-9 查询语句&#xff1a; $sql"select * from sy_guestbook where id$i"; 字符型 a-z 中文 标点符号 加入了单引号 查询语句&#xff1a; $sql"select * from sy_guestbook where gTpl$g"; simple order by 16--select * from sy_guestbook w…

【Spring】Spring AOP

Spring AOP AOP概述什么是AOP Spring AOP快速入门1.引入AOP依赖2. 编写AOP程序 Spring AOP 详解Spring AOP 核心概念切点(Pointcut)连接点(Join Point)通知(Advice)切面(Aspect) 通知类型PointCut切面优先级Order切点表达式execution表达式annotation自定义注解切面类 AOP原理代…

记录一下github深度学习的错误

解决办法&#xff1a;Anaconda\envs\pytorch_gpu\Lib\site-packages\visdom\server 修改run_server.py中注释掉第1917行的代码 def download_scripts_and_run(): #download_scripts() ~~~~~~~~这行 main() 替换static 获取方式&#xff1a;GitHub - littledee…

Vue 子传父 组件传参 defineEmits

defineEmits 属性&#xff1a;用于创建自定义事件&#xff0c;接收子组件传递过来的数据。 注意&#xff1a;如果自定义事件的名称&#xff0c;和原生事件的名称一样&#xff0c;那么只会触发自定义事件。 defineEmits 仅适用于 setup 语法糖&#xff0c;其它写法请见&#x…

docker创建镜像 Dockerfile

目录 docker的创建镜像的方式 dockerfile形成&#xff08;原理&#xff09; docker的核心作用 docker的文件结构 dockerfile的语法 CMD和ENTRPOINT的区别 创建dockerfile镜像 区别 RUN命令的优化 如何把run命令写在一块 copy和ADD区别 区别 centos7 构建Apache的d…

音视频参数介绍

一、视频参数概念 单个视频帧&#xff1a;可以简单地理解成为一张图片 单个视频帧主要的参数概念&#xff1a; 分辨率&#xff1a; 分辨率是指图像或显示器上像素的数量&#xff0c;通常用横向像素数乘以纵向像素数表示。例如&#xff0c;1920x1080 表示宽度为1920像素&…

Linux 使用 Anaconda+Uwsgi 部署 Django项目和前端项目

一、安装Anaconda 使用Anaconda创建python环境的优点&#xff1a; virtualenv只能创建系统原有的python版本&#xff0c;而不能创建创建任意版本的环境 而Anaconda的虚拟环境中&#xff0c;你可以指定任意现存可使用的python环境&#xff08;包括比原环境版本高的python版本&a…