JUC-synchorized与锁原理、锁的升级与膨胀

news2024/11/15 11:01:23

syn-ed

是一个可重入、不公平的重量级锁synchronized使用对象锁保证了临界区代码的原子性,无论使用synchorized锁的是代码块还是方法,其本质都是锁住一个对象。

  • 同步代码块,锁住的是括号里的对象
  • 同步方法
    • 普通方法,锁住的是当前实例对象,即this
    • 静态方法,锁住的是当前类对象,即class对象
// 同步代码块
synchorized(锁对象) {
}

// 普通方法
class Test{
    public synchorized test() {}
}
// 等价于
class Test{
    public void test() {
        synchronized(this) {}
    }
}

// 静态方法
class Test{
	public synchronized static void test() {}
}
// 等价于
class Test{
    public void test() {
        synchronized(Test.class) {}
	}
}

变量线程安全性

  • 成员变量和静态变量
    • 如果没有被共享,那么一定是线程安全的
    • 如果被共享:
      • 只有读操作,一定是线程安全的
      • 有读写操作,存在并发问题
  • 局部变量
    • 局部遍历是线程安全的
    • 但局部变量引用的对象则不一定
      • 如果该对象没有逃离方法的作用访问,它是线程安全的
      • 如果该对象逃离方法的作用范围,存在并发问题

常见的线程安全类

  • String
  • Integer等包装类
  • Integer
  • StringBuffer
  • Random
  • Vector
  • Hashtable
  • java.util.concurrent 包下的类
    String、Integer 等都是不可变类,因为其内部的状态不可以改变,因此它们的方法都是线程安全的,多个线程调用它们同一个实例的某个方法时,是线程安全的。

锁原理

Monitor

监视器或管程,每一个java对象都可以关联一个Monitor对象,使用synchronized给一个对象加锁(重量级锁),该对象的对象中的Mark Word就被设置指向一个Monitor对象的指针,这其实也就是重量级锁的加锁过程。

Mark Word

java对象的对象头由Mark Word、类型指针、数组长度(如果该对象是一个数组)组成。Mark Word的长度由32bit/64bit。Mark Word里默认存储对象的HashCode、分代年龄和锁标记位

  • 32位的Mark Word
    ![[Pasted image 20240719211851.png]]

  • 64位的Mark Word:
    ![[Pasted image 20240719211811.png]]

Monitor的工作流程

一个对象对应一个Monitor对象。

  • 开始时Monitor中Owner为null
  • 当 Thread-2 执行 synchronized(obj) 就会将 Monitor的所有者Owner置为Thread-2,Monitor中只能有一个Owner,obj对象的Mark Word指向Monitor,把对象原有的Mark Word存入线程栈中的锁记录
    ![[Pasted image 20240719212720.png]]
  • 在 Thread-2 上锁的过程,Thread-3、Thread-4、Thread-5 也执行 synchronized(obj),就会进入 EntryList BLOCKED(双向链表)
  • Thread-2 执行完同步代码块的内容,根据 obj 对象头中 Monitor 地址寻找,设置 Owner 为空,把线程栈的锁记录中的对象头的值设置回 MarkWord
  • 唤醒 EntryList 中等待的线程来竞争锁,竞争是非公平的,如果这时有新的线程想要获取锁,可能直接就抢占到了,阻塞队列的线程就会继续阻塞
  • WaitSet 中的 Thread-0,是以前获得过锁,但条件不满足进入 WAITING 状态的线程(wait-notify 机制)
    在这里插入图片描述

锁升级

随着竞争的增加,只能锁升级,不能降级

无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁	

偏向锁

在大多数情况下,锁总是由一个线程多次获得,让线程获得锁的代价更低而引入了偏向锁。就和名字一样,是偏向的:

  • 当线程第一次获得锁对象时,其进入偏向状态,该对象的后三位是101,同时使用CAS操作将线程ID记录到Mark Word。如果CAS操作成功,这个线程以后进入这个锁相关的同步块,查看这个线程ID是自己的就表示没有竞争,就不需要再进行任何同步操作。
  • 当另一个线程也尝试获取这个锁对象时,也会使用CAS进行替换,此时一定失败,偏向状态就会结束,撤销偏向后恢复到未锁定或轻量级锁状态。

在java中是默认开启偏向锁的,也就是说在一个对象创建的时候,其Mark Word的后三位是101,其余值均为0;当调用这个对象的hashCode时,就再也无法进入偏向状态了,即后三位是001。这是因为Mark Word会被hashCode占用。

偏向锁的撤销

  • 第一点就是我们前边提过的,调用该对象的hashcode方法。
  • 当有其它线程使用偏向锁对象时,会将偏向锁升级为轻量级锁
  • 调用 wait/notify,需要申请 Monitor,进入 WaitSet

轻量级锁

一个对象有多个线程要加锁,但加锁的时间是错开的(没有竞争),轻量级锁的使用对我们程序员来说,也是使用syn-ed来完成,只是底层的实现对我们透明的。

加锁过程
当某一个线程对一个对象进行加锁时,会在栈帧中创建一个锁记录(Lock Record),并使用==CAS将对象的Mark Word中的信息保存到该锁记录中,而Mark Word中就记录该锁记录的地址,以及锁标志位(00)。==这样就完成了加锁。但是当CAS失败的时候,此时会有两种情况导致失败:

  • 它线程已经持有了该Object的轻量级锁,我又想去获取,这时表明有竞争,进入锁膨胀过程在膨胀之前还有一个自旋的过程
  • 线程自己执行synchronized锁重入,栈帧中还会存在一条Lock Record作为重入的计数,但是每次重入都会有CAS,所以才引入了偏向锁进行优化

解锁过程(当退出synchronized代码块)

  • 如果有取值为null的锁记录,表示有重入,这时重置锁记录,表示重入计数减 1
  • 如果锁记录的值不为null,这时使用CAS将 Mark Word的值恢复给对象头
    • 成功,则解锁成功
    • 失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程。

重量级锁

在尝试加轻量级锁的过程中,CAS操作无法成功,可能是其它线程为此对象加上了轻量级锁(有竞争),这时需要进行锁膨胀,将轻量级锁变为重量级锁

  • 当线程1使用CAS对一个对象obj进行加锁时,发现线程1已经持有该轻量锁,此时就会失败并导致锁膨胀
  • 然后就会为obj对象申请Monitor锁,通过obj对象头获取到持锁线程,将Monitor的 Owner置为线程0,将obj的对象头指向重量级锁地址,然后自己进入Monitor的EntryList而BLOCKED。
  • 当线程0释放锁时,使用CAS将Mark Word的值恢复给对象头失败,这时进入重量级解锁流程,即按照 Monitor地址找到Monitor对象,设置Owner为 null,唤醒EntryList中BLOCKED线程
    ![[Pasted image 20240719223237.png]]

![[Pasted image 20240719222445.png]]

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

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

相关文章

手写文件系统一条龙篇

哈喽,我是子牙老师。这篇文章聊聊文件系统是怎么写出来的,看完,你就可以自己去写文件系统了。本文以Linux的EXT系列文件系统为例进行讲解,理解了,其他的文件系统你就可以自行研究了,差不多的东西 理解了本…

第二证券:市场估值依然处于较低区域

结合风格板块、一级工作预喜情况与工作中预喜崎岖较大的企业体现看,估量2024年上半年中下游工作获利改善势头向好。其中,获益于客运量的上升,交通运输工作中大型蓝筹公司盈余才干改善。TMT领域中电子及通讯工作成果上升崎岖较大,工…

微服务分布式事务

1、分布式事务是什么? 微服务架构中的分布式事务是指在多个服务实例之间保持数据一致性的机制。由于微服务通常涉及将业务逻辑拆分成独立的服务,每个服务可能有自己的数据库,因此当一个业务操作需要跨多个服务进行时,确保所有服务…

小白速通 Spring 之 Annotation 篇

Annotation 注解 Service public class MessageServiceImpl implements MessageService{public String getMessage() {return "Hello World!";}} 本质上来说 Annotation(注解)是 Java 推出的一种注释机制,后面我们统一叫 Annotation,和普通的注释有个显…

Python设计模式:巧用元类创建单例模式!

✨ 内容: 今天我们来探讨一个高级且实用的Python概念——元类(Metaclasses)。元类是创建类的类,它们可以用来控制类的行为。通过本次练习,我们将学习如何使用元类来实现单例模式,确保某个类在整个程序中只…

python-首字母移位(PythonTip)

[题目描述] 编写一个程序,将句子中每个单词的首字母移位到下一个单词。定义函数shift_first_letter(),参数为sentence(字符串)。在函数内,将句子中每个单词的首字母移位到下一个单词。最后一个单词的首字母移位到句子的…

Hadoop架构

一、案列分析 1.1案例概述 现在已经进入了大数据(Big Data)时代,数以万计用户的互联网服务时时刻刻都在产生大量的交互,要处理的数据量实在是太大了,以传统的数据库技术等其他手段根本无法应对数据处理的实时性、有效性的需求。HDFS顺应时代…

【机器学习】模型验证曲线(Validation Curves)解析

🌈个人主页: 鑫宝Code 🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础 ​💫个人格言: "如无必要,勿增实体" 文章目录 模型验证曲线(Validation Curves)解析什么是模型验证曲线?模型验证曲线的解读模…

Django教程(004):基于orm操作数据库的用户管理实现

文章目录 1、功能需求2、展示用户列表2.1 添加url2.2 创建视图2.3 编写html页面 3、添加用户3.1 添加url3.2 跳转到添加页面3.3 编写添加用户页面3.4 添加用户3.5 实现效果3.6 页面优化 4、删除用户4.1 添加删除用户按钮4.2 添加删除url4.3 删除用户4.4 实现效果 5、完整代码链…

vue3使用html2canvas

安装 yarn add html2canvas 代码 <template><div class"container" ref"container"><div class"left"><img :src"logo" alt"" class"logo"><h2>Contractors pass/承包商通行证&l…

StableDiffusion模型推荐系列(风格型)

今天&#xff0c;分享几个SDXL的特殊风格模型&#xff0c;这些模型在特定风格下非常出彩&#xff0c;弥补了一些“我已经看腻了AI画图”的情况。这几位作者分享的SDXL模型艺术风格上表现得尤为出色&#xff0c;而且他们都是秉持着开源精神免费分享自己的模型。训练过模型的小伙…

掌握VR全景技术,需要具备哪些条件?

VR全景技术自从进入市场以来&#xff0c;就在各个行业领域尝试落地运用&#xff0c;包括但不限于广告宣传、学校教育、医疗、工业、农业等领域。随着5G 技术的不断普及&#xff0c;VR全景技术也逐渐被应用到日常生活中的各个方面&#xff0c;从地产中介到车企销售&#xff0c;从…

单周期CPU(三)译码模块(minisys)(verilog)(vivado)

timescale 1ns / 1ps //module Idecode32 (input reset,input clock,output [31:0] read_data_1, // 输出的第一操作数output [31:0] read_data_2, // 输出的第二操作数input [31:0] Instruction, // 取指单元来的指令input [31:0] …

ubuntu配置ssh服务器详解

① 确定Ubuntu是否安装SSH服务 systemctl status ssh 一般最开始都没有ssh服务 ② 安装SSH Server sudo apt install openssh-server 执行过程如下 ③ 确定Ubuntu SSH服务状态 systemctl status ssh 现在能看到&#xff1a; 第一行加载状态&#xff0c;已加载ssh.service文件…

大语言模型-GPT-Generative Pre-Training

一、背景信息&#xff1a; GPT是2018 年 6 月由OpenAI 提出的预训练语言模型。 GPT可以应用于复杂的NLP任务中&#xff0c;例如文章生成&#xff0c;代码生成&#xff0c;机器翻译&#xff0c;问答对话等。 GPT也采用两阶段的训练过程&#xff0c;第一阶段是无监督的方式来预训…

使用 Redis 实现验证码、token 的存储,用自定义拦截器完成用户认证、并使用双重拦截器解决 token 刷新的问题

基于session实现登录流程 1.发送验证码 用户在提交手机号后&#xff0c;会校验手机号是否合法&#xff0c;如果不合法&#xff0c;则要求用户重新输入手机号 如果手机号合法&#xff0c;后台此时生成对应的验证码&#xff0c;同时将验证码进行保存&#xff0c;然后再通过短信…

Python爬虫实战案例(爬取图片)

爬取图片的信息 爬取图片与爬取文本内容相似&#xff0c;只是需要加上图片的url&#xff0c;并且在查找图片位置的时候需要带上图片的属性。 这里选取了一个4K高清的壁纸网站&#xff08;彼岸壁纸https://pic.netbian.com&#xff09;进行爬取。 具体步骤如下&#xff1a; …

Android 性能之刷新率设置和管理

目录 1. 刷新率和帧率 2. 多种刷新率 3. 基本原理 3.1 屏幕 & 显示控制器 3.2 Composer Service 4. Framework 策略 4.1基本架构 4.2 刷新率设置项的定义 4.2.1 最低刷新率 4.2.2 默认刷新率 & 默认的用户设置刷新率 4.2.2.1 设置入口 4.2.2.2 设置场景 4…

Matlab画不同指标的对比图

目录 一、指标名字可修改 二、模型名字可修改 三、输入数据可修改 软件用的是Matlab R2024a。 clear,clc,close all figure1figure(1); % set(figure1,Position,[300,100,800,600],Color,[1 1 1]) axes1 axes(Parent,figure1);%% Initialize data points 一、指标名字可修…

zigbee DL-20无线串口模块(电赛备战)

zigbee DL-20无线串口模块(电赛备战) 备战2024电子设计大赛&#xff08;7.29-8.1&#xff09; 概述 DL-20是一款2.4G无线串口模块&#xff0c;支持点对点和广播模式的通信。它具备低数据丢失率、宽电压范围和高传输速率的特点&#xff0c;适用于多种无线通信场景。 在电赛中&…