JAVA锁相关的概念和分类

news2025/4/27 14:06:30

JAVA对象和对象头

  • java中object对象一般由对象头、示例数据、填充字节三部分组成
  • 其中填充字节是为了补全对象大小为8bit的倍数而存在,没太多功能性要求
  • 对象头包括mark word和class point
    • class point存放的是指向堆中数据类型的指针
    • mark word是存储了许多和当前对象运行状态有关的数据,包括hashcode,锁标志位等
    • 其中,锁标志位是2bit,取值分别为00/01/10/11,分别对应的是轻量级锁、无锁或者偏向锁、轻量级锁、GC标记

在这里插入图片描述

  • 在jvm中,资源加锁、解锁和唤起线程时,切换线程会耗费较大的性能资源,从java6之后,引入了轻量级锁和重量级锁的概念,参考这篇
    • 由低到高依次为无锁、偏向锁、轻量级锁、重量级锁,锁只能升级不能降级。
    • 无锁:多线程对资源不存在竞争关系,或者竞争关系中,不想通过加锁的机制去控制,例如CAS机制就是无锁编程,CAS在操作系统中是通过一条指令来实现,所以就能保持原子性。如果一个线程多次访问同一资源,并且没有其他资源争夺,可升级为偏向锁。
    • 偏向锁:给指定的某个线程开放锁,偏爱某一个线程,在对象头中,判断锁标志位如果为01,再判断倒数第二位,是否为偏向锁,如果是偏向锁,再去对象头前23位获取线程的ID,判断当前请求的线程是否为偏向线程,如果是就开放资源。如果多个线程在同一时间想要获取同一把锁,产生了锁竞争,就会变为轻量级锁。
    • 轻量级锁:多个线程在同一时间想要获取同一把偏向锁,轻量级锁会把对象的mark word和线程栈中的lock record进行一一对应。同时其他没有获取资源的线程会不断重试,叫做自旋,默认自旋10次,但是可以配置jvm自旋参数。如果自旋超过最大次数,就会升级为重量级锁。
    • 重量级锁:如果轻量级锁中其他线程自旋超过最大次数,就会升级为重量级锁。如果一个线程在占据资源锁的同时,另一个线程也要访问该资源,那么就暂时无法访问并且进行线程自旋。
      • 自旋的意思就是定时重复尝试获取资源,当有线程产生自旋时,即升级为重量级锁。
      • 自旋的次数默认是10,所以不会出现死循环。
      • 长时间的自旋操作是非常消耗资源的,一个线程持有锁,其他线程就只能在原地空耗CPU,执行不了任何有效的任务,这种现象叫做忙等(busy-waiting)。
      • 当后续线程尝试获取锁时,发现被占用的锁是重量级锁,则直接将自己挂起(而不是忙等)。
      • 重量级锁会有monitor监控机制,monitor可以看做只能同时允许容纳一个线程的管道,如果反编译代码中synchronize的class文件,会发现字节码中有monitorenter和monitorexit,分别控制线程的进入和离开。下图为monitor的机制图:
        在这里插入图片描述
        在这里插入图片描述
CAS:compare and swap,乐观锁,其实是无锁,利用业务上的字段匹配机制进行判断
  • CAS操作包含三个操作数——内存位置(V)、期望值(A)和新值(B):
    如果内存位置的值与期望值匹配,那么处理器就会自动将该位置值更新为新值,否则,处理器不做任何操作;无论那种情况,它都会在CAS指令之前返回该位置的值;
    ABA 问题

AQS:AbstractQueuedSynchronizer

  • java.util.concurrent.locks
  • 线程的两种模式?独占模式和共享模式?
  • AQS提供两种获取资源的模式:
    1. 如果没获取到资源,那么就放弃或者执行别的逻辑,使用aqs的tryAcuquire
    2. 如果没获取到资源,那么就一直自旋尝试重新获取,使用aqs的aquire
  • tryAcquire
class test extends AbstractQueuedSynchronizer{
	@Override
	protected boolean tryAcquire(int arg){
		// 自定义业务逻辑
		if(arg !=1 ){
			return false;
		}
		if(getState()==1){
			return false;	
		}
		return compareAndSetState(0, 1);
	}
}
  • acquire

在这里插入图片描述
在这里插入图片描述

参考这篇

乐观锁、悲观锁

点击链接
使用for update实现分布式锁;

  • 乐观锁适用于写比较少的情况下,即冲突真的很少发生的时候,这样可以省去锁的开销,加大了系统的整个吞吐量;如果经常产生冲突,上层应用会不断的进行重试,这样反倒是降低了性能,所以这种情况下用悲观锁就比较合适。
  • Java里使用的各种锁,几乎全都是悲观锁。synchronized从偏向锁、轻量级锁到重量级锁,全是悲观锁。JDK提供的Lock实现类全是悲观锁。其实只要有“锁对象”出现,那么就一定是悲观锁。因为乐观锁不是锁,而是一个在循环里尝试CAS的算法。
  • JDK并发包中为数不多的乐观锁:JUC.atomic中的原子类都是利用乐观锁实现的。
可重入锁
  • JDK提供的所有现成的Lock实现类,包括synchronized关键字锁都是可重入的
  • 如果需要不可重入锁,则需要自己实现了。
  • 不可重入锁很容易造成对象死锁,以下面代码为例:
// 如果锁是具有可重入性的话,那么该线程在调用 test2 时并不需要再次获得当前对象的锁,可以直接进入 test2 方法进行操作。
// 如果锁是不具有可重入性的话,那么该线程在调用 test2 前会等待当前对象锁的释放,实际上该对象锁已被当前线程所持有,不可能再次获得。
// 如果锁是不具有可重入性特点的话,那么线程在调用同步方法、含有锁的方法时就会产生死锁。
public sychrnozied void test() {
    xxxxxx;
    test2();
}
 
public sychronized void test2() {
    yyyyy;
}

类锁和对象锁
  • 类锁:如果有n个加锁的静态方法,在多线程情况下,其中一个线程访问了这个类的某个静态方法,则这个类其他加锁的静态方法不能被访问,要等被访问的那个方法彻底执行完,其他方法才可被调用,不加锁的方法不参与
  • 对象锁:一个对象有n个加锁的方法,在多线程情况下,其中一个线程访问了这个对象的某个加锁的非静态方法,这个对象的加锁的其他非静态方法不能被访问,要等访问的那个方法彻底执行完,其他方法才可执行调用,不加锁的不参与(不同对象无法互相影响)

创建一个Object对象后加锁,和直接对本对象加锁,有什么区别?

  • 如下图所示,a方法加的是对象级别的锁,锁的范围仅对本示例有效;b方法假的是类级别的锁,一旦加锁,其他所有的示例也会被锁住。
  • 所以一般情况下还是创建一个object后进行对象加锁,单例模式下可以使用类锁
	public class Test{
		Object lock = new Object();
		public void a(){
			synchronized(lock){
				// ...
			}
		}
		public void b(){
			synchronized(Test.class){
				// ...
			}
		}
	}
独享锁/共享锁
  • 共享锁是指该锁可被多个线程所持有。对于Java ReentrantLock而言,其是独享锁。但是对于Lock的另一个实现类ReentrantReadWriteLock,其读锁是共享锁,其写锁是独享锁。
  • S锁,共享锁或读锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。
  • X锁,互斥锁或写锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。
公平锁/非公平锁
锁的性能?

synchronized 代码块>synchronized 同步方法>类锁

AQS

AQS的来实现线程调度

java死锁后怎么办?
锁粗化/锁消除

锁消除是指虚拟机即时编译器在运行时,对一些代码上要求同步,但是被检测到不可能存在共享数据竞争的锁进行消除。锁消除的主要判定依据来源于逃逸分析的数据支持,如果判断在一段代码中,堆上的所有数据都不会逃逸出去从而被其他线程访问到,那就可以把它们当做栈上数据对待,认为它们是线程私有的,同步加锁自然就无须进行。

如果一系列的连续操作都对同一个对象反复加锁和解锁,甚至加锁操作是出现在循环体中的,那即使没有线程竞争,频繁地进行互斥同步操作也会导致不必要的性能损耗。如果虚拟机探测到有这样一串零碎的操作都对同一个对象加锁,将会把加锁同步的范围扩展(粗化)到整个操作序列的外部

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

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

相关文章

Linux配置和使用Git

本文已收录至《Linux知识与编程》专栏! 作者:ARMCSKGT 演示环境:CentOS 7 ​ 目录 前言 正文 注册Giett构建仓库 注册giett 构建仓库 Linux配置Git 下载Git 配置Git用户名 配置Git账户邮箱 验证是否初始化成功 生成授权证书 获…

重新认识 React Hooks useContext

通常来说,React 数据的传递方式都是一层一层把资料 props 传到子层的 就算第二层(Function Component)、第三层(Button Group Compontn) 根本没有用到这个资料,但是为了传到最底层(button) ,每一层还是必须要传props // App.js const App = () => {const [dark, setDark…

vue3:加载本地图片等静态资源

背景 在我们用 vue2 webpack 的时候&#xff0c;加载图片资源是这样用的&#xff1a; <img :src"require(/assets/test.png)" />这样打包后就会触发 file-loader 打包图片资源&#xff0c;在 dist 文件夹中就可以看到这个图片&#xff08;如果图片较小会打包…

Vue3+vite4使用mockjs进行模拟开发遇到的坑

Vue3vite4使用mockjs进行模拟开发遇到的坑 最近没那么忙了&#xff0c;就想着自己写一个后台管理系统的小demo。刚好最近把Vue3的文档撸了一遍&#xff0c;正好可以顺便练习一下Vue3ts。 插件 1、mockjs是必不可少的。 2、vite-plugin-mock。由于现在创建Vue3项目默认都使用vit…

Django框架之配置信息

静态文件 项目中的CSS、图片、js都是静态文件。一般会将静态文件放到一个单独的目录中&#xff0c;以方便管理。在html页面中调用时&#xff0c;也需要指定静态文件的路径&#xff0c;Django中提供了一种解析的方式配置静态文件路径。静态文件可以放在项目根目录下&#xff0c…

2023年,pmp项目管理师证书有用么?难考吗?

一、这个证书含金量高么&#xff1f; 是高的&#xff0c;在项目管理或者管理领域中&#xff0c;知名度和含金量都是在前列的。看项目岗位要求&#xff1a;“PMP证书优先”&#xff0c;“”具备项目管理资质&#xff08;PMP&#xff09;优先“。 且在行业内几乎是共识了&#…

2023最新软件测试八股文,能不能拿Offer就看你背得怎样了

前言鉴于目前测试就业越来越严峻&#xff0c;内卷也成了测试领域的代名词了。我的一个HR朋友告诉我&#xff0c;由于门槛较低&#xff0c;现在普通测试岗&#xff08;偏功能&#xff09;的投递比已经将近100&#xff0c;也就是一个岗位差不多有百分简历投进来。 所以现在还想从…

【机器学习】lightGBM是什么?

梯度提升法(Gradient Boosting Machine&#xff0c;简记 GBM)以非参数方法&#xff08;不假设函数形式&#xff09;估计基函数&#xff0c;并在“函数空间”使用“梯度下降”进行近似求解。非参数方法包括K近邻法、决策树、以及基于决策树的装袋法、随机森林与提升法等。 01 梯…

MySQL-Innodb引擎事务原理

文章目录1.事务介绍2 事务特性3. 事务的实现原理4 redo log 保证持久性5 undo log 保证原子性6 MVCC 概念6.1 隐藏字段6.2 版本链6.3 ReadView6.3.1readview 版本控制规则7 隔离性 实现7.2 隔离性- REPEATABLE READ 可重复读下8 一致性1.事务介绍 事务是一组操作的集合&#xf…

Vue (4)

文章目录1. 绑定样式1.1 绑定 class 样式1.2 绑定 style 样式2. 条件渲染2.1 v-show2.2 v-if3. 列表渲染3.1 v-for3.2 key 的作用与原理3.3 列表过滤3.4 列表排序1. 绑定样式 说 绑定样式 前&#xff0c;先准备好 以下几个 样式 : <style>.basic {width: 400px;height: 1…

四数之和(详细题解:双指针+排序)

18. 四数之和 难度中等1502 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#x…

Java 魔法类 Unsafe 详解

阅读过 JUC 源码的同学&#xff0c;一定会发现很多并发工具类都调用了一个叫做 Unsafe的类。 那这个类主要是用来干什么的呢&#xff1f;有什么使用场景呢&#xff1f;这篇文章就带你搞清楚&#xff01; Unsafe 介绍 Unsafe 是位于 sun.misc 包下的一个类&#xff0c;主要提…

要发计算机SCI论文,参考文献应该怎么引用? - 易智编译EaseEditing

SCI论文发表中经常被引用的参考文献主要有以下四种。 一是关于具体的实验的方法&#xff0c;二是支持性或者有冲突的证据&#xff0c;三是比较有用的类似的文献&#xff0c;四是有历史背景的和有意义的文献。 其实归根到底&#xff0c;你引用的SCI的参考文献必须对你的论文发表…

031_SSS_Imagic Text-Based Real Image Editing with Diffusion Models

Imagic: Text-Based Real Image Editing with Diffusion Models 1. Introduction 本文提出了一种新的基于Diffusion的方法称作Imagic&#xff0c;可以实现复杂的基于文本的图像编辑。与之前的方法不同&#xff0c;本文的方法只需要一张输入图像和一个目标文本&#xff0c;并且…

线程私有变量ThreadLocal详解

本文已收录至Github&#xff0c;推荐阅读 &#x1f449; Java随想录 烈火试真金&#xff0c;逆境试强者。——塞内加 文章目录什么是ThreadLocalThreadLocal 原理set()方法get()方法remove()方法ThreadLocal 的Hash算法ThreadLocal 1.7和1.8的区别ThreadLocal 的问题ThreadLoca…

StarRocks获评「2022 中国开源社区健康案例」!

近日&#xff0c;OSCHINA 2022年度中国开源项目评选结果正式揭晓&#xff0c;StarRocks开源社区成功入选 OSCHINA “2022中国开源社区健康案例”&#xff01;开源社区健康指的是围绕一个开源项目形成的社区中关于项目的技术迭代、社区的组织架构、成员构成、开源治理、上下游协…

【手写 Vuex 源码】第十二篇 - Vuex 插件机制的实现

一&#xff0c;前言 上一篇&#xff0c;主要介绍了 Vuex 插件的开发&#xff0c;主要涉及以下几个点&#xff1a; Vuex 插件的使用介绍&#xff1b;Vuex 插件开发和使用分析&#xff1b;Vuex 插件机制的分析&#xff1b; 本篇&#xff0c;继续介绍 Vuex 插件机制的实现&…

moveToCoordinateF3DconcatenateRotations

moveToCoordinate 演示视频: 注意:前提是3~6轴机器人机构且不是PickAndPlace 该方法_3D。Poses.moveToCoordinate 移动由 指定的对象,该对象 对应于支持的机器人配置之一,只要标识的机器人配置支持,其第一个动画指向指定坐标和指定旋转。这无需您定义姿势即可工作。 工…

Python期末复习知识点大合集(期末不挂科版)

Python期末复习知识点大合集&#xff08;期末不挂科版&#xff09; 文章目录Python期末复习知识点大合集&#xff08;期末不挂科版&#xff09;一、输入及类型转换二、格式化输出&#xff1a;字符串的format方法三、流程控制四、随机数生成五、字符串六、序列索&#xff08;含字…

stm32f407探索者开发板(十五)——NVIC中断优先级管理

文章目录零、前言一、NVIC中断优先级分组1.1 中断的管理方法1.2 抢占优先级&相应优先级的区别1.3 举例1.4 特别说明1.5 中断优先级分组函数二、NVIC中断优先级设置2.1 中断设置相关寄存器2.2 中断设置优先级2.2.1 中断优先级控制的寄存器组 IP[240]2.2.2 中断使能寄存器组 …