[Java EE] 多线程(七): 锁策略

news2024/11/18 3:23:14

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(93平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

1.几种不同的锁策略

常见的锁策略不仅仅是局限于Java中,任何语言都适用.

1.1 乐观锁vs悲观锁

  • 乐观锁:加锁的时候,预测锁冲突的概率比较小,所以在接下来的时间里做的事情就比较少,也就是加锁的开销就比较小.但是具体是怎么判断加锁之后锁冲突的概率的,这就和JVM的源代码有关联了.
  • 悲观锁:加锁的时候,预测锁冲突的概率比较大,所以在接下来的时间里做的事情就比较多,也就是加锁的开销就比较大.

举例说明:找老师问问题
现在有A和B两个同学:同学A采用悲观锁的策略,同学B采用乐观锁的策略
同学A就会想:"我去了老师办公室之后,老师也不一定有时间回答."所以就会给老师提前发微信,询问老师是否有时间得到肯定答复之后才会来问问题.
同学B就会想:"我去了之后老师肯定有时间回答."所以就会直接找老师帮忙,如果老师比较闲,那么问题便得已解决,如果老师比较忙,也不会打扰到老师.

什么时候使用乐观锁策略,什么时候使用悲观锁策略,还是要看具体的场景.
就如上述的例子,如果老师确实比较忙,使用悲观锁就是很好的策略,如果使用乐观锁,就是白跑一趟.
老师确实比较闲的时候,使用乐观锁就是很好的策略,如果使用悲观锁,就会额外消耗加锁的开销.

1.2 重量级锁vs轻量级锁

一般来说,轻量级锁对应的就是乐观锁,重量级锁对应的就是悲观锁,两组概念经常被混起来用.
我们现在来解释一下,重量级锁究竟比轻量级锁多做了哪些事情,就是轻量级锁值通过用户态代码来加锁,而重量级锁就是通过系统内核提供的mutex来加锁,也就是通过内核态实现加锁.
在这里插入图片描述

1.3 自旋锁vs挂起等待锁

自旋锁是轻量级锁的典型实现方式,挂起等待锁是重量级锁的典型实现方式.

  • 自旋锁: 按之前的方式,线程抢占锁失败就会进入阻塞等待状态,放弃CPU.
    但实际上,大部分情况下,虽然当前抢占锁失败,但是过了不久之后,锁就会被立刻释放掉,现在就没必要放弃CPU,这时候就可以使用自旋锁的方式来解决上述问题
void locker(){
	while(true){
		if(锁是否被占用){
			continue;
		}
		获取到锁;
		break;
	}
}

从上述伪代码中,我们可以看到自旋锁采用了忙等的策略,如果获取锁失败,就立即再尝试获取锁,无限循环,直到获取到锁为止.
这种锁的优点就是:没有放弃CPU,不涉及阻塞和调度,一旦锁被释放,就可以第一时间获取到锁.
缺点就是:消耗了更多的CPU资源,其他线程可能吃不到CPU资源.

  • 挂起等待锁:就是在一个线程与其他线程产生锁冲突的时候,就会挂起等待,线程不再采用忙等的方式,而是阻塞等待,直到这个锁被释放,然后系统可以唤醒线程,再去尝试重新获取锁.

优点:不会占用CPU资源,可以把CPU资源让给其他的线程.
缺点:需要系统去唤醒该线程,再去获取锁,这样就不可以第一时间获取到锁.

举例说明:
有请老朋友:钟离,达达利亚,荧
如果达达利亚和荧去表白,但是现在荧告诉他,他现在有男朋友,但是达达利亚是个死皮赖脸的人,一直每天给荧发消息问候寒暄.一旦荧和现男友分手,达达利亚就立马可以上位.
如果钟离和荧去表白,但是现在荧也告诉他,他现在有男朋友,由于钟离比较收敛,不再去天天烦荧.但是有一天他从别人口中听说荧分手了,此时钟离才有机会上位.
在这里插入图片描述

1.4 公平锁vs非公平锁

假设三个线程A,B,C.A先尝试获取锁,获取成功.然后B再尝试获取锁,获取失败,阻塞等待;然后C也尝试获取锁,C也获取失败,也阻塞等待.

  • 公平锁: 遵守先来后到的原则,B比C等待的时间长,在A释放锁之后,B就可以优先加锁.
  • 非公平锁: 不遵循先来后到的原则,B和C获取到锁的概率是相等的.就看谁的竞争能力比较强.

举例说明:
荧和他的男朋友在谈恋爱,突然有一天分手了,这时候达达利亚和钟离都有机会追到荧.但是现在达达利亚却比钟离追荧的时间长.
如果是公平锁的话:由于达达利亚追荧的时间比较长,那么达达利亚可以优先追到荧.
如果是非公平锁的话:这时就和追的时间没有关系了,这时候两个人追到荧的概率就是相等的,就各凭本事了.

注意:

  • 操作系统由于线程是随机调度的,这时候不做任何限制的话,那么锁就是非公平的.如果想要实现公平锁的话,必须借助额外的数据结构来判断等待时间.
  • 公平锁和非公平锁没有好坏之分,主要看使用场景.

1.5 不可重入锁vs可重入锁

前面提级过,不再赘述.
https://blog.csdn.net/2301_80050796/article/details/138041540?spm=1001.2014.3001.5501

1.6 读写锁

一个线程对于数据的访问,主要存在两种操作:读数据和写数据.

  • 两个线程都只是读一个数据,此时并没有线程安全问题,直接并发读取即可.读加锁和读加锁之间并不会产生锁互斥.
  • 如果两个线程有一个读,有一个写,此时有线程安全问题,写加锁和读加锁之间会有锁互斥.
  • 如果两个线程都在写一个数据,此时就有线程安全问题,写加锁和写加锁之间会产生锁互斥.

读写锁非常适合用在,频繁读,不频繁写的场景中.

2. synchronized原理

2.1 基本特点

  • 一开始是轻量级锁(乐观锁),如果锁冲突比较频繁,就升级为重量级锁(悲观锁)
  • 实现轻量级锁的时候大概率是使用自旋锁的策略.
  • 是一把不公平锁
  • 是可重入锁
  • 不是读写锁

2.2 synchronized的锁升级

JVM将synchronized锁分为无锁、偏向锁、轻量级锁、重量级锁状态.会根据情况,进⾏依次升级.
在这里插入图片描述

  1. 偏向锁(重点)
    第一个尝试加锁的线程,先不会对线程真正加锁.而是先进入偏向锁状态.
    偏向锁不是真正的加锁,而只是给对象头中做一个"偏向锁的标记",记录这个锁属于哪个线程,如果后期没有其他线程来与该线程进行锁竞争,那么就一直保持这个状态,就减少了加锁的开销.
    偏向锁就突出了一个字"懒",能不加锁就不加锁,避免了加锁带来的不必要的开销.但是这个偏向锁的标记又不得不做,否者分不清何时哪个线程需要真正加锁.
  2. 轻量级锁
    当有其他线程尝试与该线程进行锁竞争的时候,此时偏向锁就会升级为轻量级锁,
  3. 重量级锁
    当锁冲突不断加深的时候,就会升级为重量级锁.

举例说明:
此时比如荧和达达利亚是游走在朋友和男女朋友之间的关系,这时候如果没有其他人来与达达利亚竞争荧的时候,就一直可以保持这种关系(一直保持偏向锁),就避免了官宣这种开销比较大的操作,将来如果达达利亚想分手的时候,一句话直接让荧闭嘴:“你又不是我女朋友”.
如果有一天钟离也对荧有了感情,想要追荧,这时候达达利亚就可以立即和荧官宣,这种开销就比较大了(加锁操作),就意味着达达利亚要对荧负责了,将来如果想分手的时候,也非常麻烦,需要达达利亚一顿组合技才可以把荧踹掉.

2.3 synchronized锁优化

2.3.1 锁消除

编译器+JVM判断锁是否可消除.如果可以,就直接消除.
那么什么是锁消除呢?
有一些程序的代码中,虽然使用了synchronized关键字,但是是在单线程状态下的,比如下面这个例子.

StringBuffer sb = new StringBuffer();
sb.append("a");
sb.append("b");
sb.append("c");

上述的StringBuffer操作中,每一个append方法都会涉及加锁和解锁操作,但是这是在单线程状态下进行的,这时候就没有必要再进行加锁操作,系统就会把这层锁优化掉.

2.3.2 锁粗化

⼀段逻辑中如果出现多次加锁解锁,编译器+JVM会⾃动进⾏锁的粗化.

  • 锁的粒度
    主要看该加锁范围中包含代码的多少,包含的代码越多,就认为锁的粒度越粗,反之越细.
    在这里插入图片描述
    在我们实际开发中,使用细粒度的锁是为了避免在没有加锁的情况下,避免与其他的线程产生冲突,从而产生线程安全问题.
    但是在实际上可能并没有其他线程来抢占这个锁,这时候JVM就会自动把这几个锁粗化成更少的锁,从而减少加锁解锁的系统开销.

举例说明:
有请助教:滑稽老铁
滑稽⽼哥当了领导,给下属交代⼯作任务:⽅式⼀: • 打电话,交代任务1,挂电话. • 打电话,交代任务2,挂电话. • 打电话,交代任务3,挂电话.⽅式⼆: • 打电话,交代任务1,任务2,任务3,挂电话.显然,方式二是更高效的方案.

我们通过上面的解释可以看到,synchronized背后做的事情是非常多的,目的就是为了让Java程序员们即使不懂这些东西也可以写出高质量的代码.Java的大佬真的是为我们操碎了心!!
在这里插入图片描述

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

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

相关文章

ZOC8 for Mac v8.08.1激活版:卓越性能的SSH客户端

在远程连接和管理的世界中,ZOC8 for Mac以其卓越的性能和丰富的功能,成为了众多专业人士的首选SSH客户端。它支持SSH1、SSH2、Telnet、Rlogin、Serial等多种协议,让您轻松连接到远程服务器。ZOC8拥有简洁直观的界面和强大的功能设置&#xff…

VMware虚拟机中ubuntu使用记录(6)—— 如何标定单目相机的内参(张正友标定法)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、张正友相机标定法1. 工具的准备2. 标定的步骤(1) 启动相机(2) 启动标定程序(3) 标定过程的操作(5)可能的报错 3. 标定文件内容解析 前言 张正友相机标定法…

语义分割——铁路轨道数据集

引言 亲爱的读者们,您是否在寻找某个特定数据集,用于研究或项目实践?欢迎您在评论区留言,或者通过公众号私信告诉我,您想要的数据集的类型主题。小编会竭尽全力为您寻找,并在找到后第一时间与您分享。 重…

typescript 对象数组和函数

typescript 对象数组和函数 对象 在JavaScript中,对象属于非原始类型。对象也是一种符合数组类型,由若干个对象属性构成。对象属性可以是任意数据类型,比如数组,函数或者对象等。当对象属性为函数的时候,称为方法。 …

vue3--element-plus-抽屉文件上传和富文本编辑器

一、封装组件 article/components/ArticleEdit.vue <script setup> import { ref } from vue const visibleDrawer ref(false)const open (row) > {visibleDrawer.value trueconsole.log(row) }defineExpose({open }) </script><template><!-- 抽…

Java与Go: 生产者消费者模型

什么是生产者消费者模型 生产者-消费者模型&#xff08;也称为生产者-消费者问题&#xff09;是一种常见的并发编程模型&#xff0c;用于处理多线程或多进程之间的协同工作。该模型涉及两个主要角色&#xff1a;生产者和消费者&#xff0c;一个次要角色&#xff1a;缓冲区。 生…

全方位解析Node.js:从模块系统、文件操作、事件循环、异步编程、性能优化、网络编程等高级开发到后端服务架构最佳实践以及Serverless服务部署指南

Node.js是一种基于Chrome V8引擎的JavaScript运行环境&#xff0c;专为构建高性能、可扩展的网络应用而设计。其重要性在于革新了后端开发&#xff0c;通过非阻塞I/O和事件驱动模型&#xff0c;实现了轻量级、高并发处理能力。Node.js的模块化体系和活跃的npm生态极大加速了开发…

【React】React-redux多组件间的状态传递

效果&#xff08;部分完整代码在最底部&#xff09;&#xff1a; 编写 Person 组件 上面的 Count 组件&#xff0c;已经在前面几篇写过了&#xff0c;也可以直接翻到最底部看 首先我们需要在 containers 文件夹下编写 Person 组件的容器组件 首先我们需要编写 index.jsx 文件…

一种算法分类方式及其应用

在计算机科学领域&#xff0c;算法是解决问题的有效方法&#xff0c;而对算法进行分类有助于理解它们的特性、优劣以及在不同场景下的应用。常见的算法分类方法&#xff0c;包括按设计思想、问题类型、数据结构和应用领域等&#xff0c;每一类算法会对应有其典型和实际应用。 算…

连接HiveMQ代理器实现MQTT协议传输

先下载MQTTX: MQTTX: Your All-in-one MQTT Client Toolbox 使用线上免费的MQTTX BROKER:The Free Global Public MQTT Broker | Try Now | EMQ 打开MQTTX&#xff0c;创建连接&#xff0c;点击NEW SUBSCRIPTION,创建一个主题&#xff0c;这里使用test/topic,在下面Json中填写…

大语言模型教程与实践(开源)

1.简介 大语言模型&#xff08;Large Language Models, LLMs&#xff09;的兴起确实始于OpenAI在2018年发布的GPT&#xff08;Generative Pre-trained Transformer&#xff09;&#xff0c;这一开创性工作引领了自然语言处理领域的新纪元。随后&#xff0c;2022年底ChatGPT的横…

DDD:根据maven的脚手架archetype生成ddd多模块项目目录结构

随着领域驱动的兴起&#xff0c;很多人都想学习如何进行ddd的项目开发&#xff0c;那ddd的项目结构是怎么样的&#xff1f;又是如何结合SpringBoot呢&#xff1f;那么针对这个问题&#xff0c;笔者使用maven的archetype封装一个相对通用的ddd的项目目录&#xff0c;方便一键生成…

Redisson 分布式锁和同步器

系列文章目录 文章目录 系列文章目录前言前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 redisson 是基于redis的扩展库,使得redis除了应用于缓存以外,还能做队列…

Excel 批量创建sheet页

参考资料 最巧妙的Excel批量创建工作表方法 一. 需求 ⏹有如下模板&#xff0c;现想根据提供的姓名&#xff0c;批量创建sheet页&#xff0c;要求每个sheet页拥有相同的模板 二. 通过透视表&#xff0c;批量创建sheet页面 ⏹如下图所示的步骤&#xff0c;创建透视表后&#…

3.3Java全栈开发前端+后端(全栈工程师进阶之路)-前端框架VUE3框架-企业级应用-Vue组合式API

为什么要使用Composition API 一个Options API实例 在前面的课程中&#xff0c;我们都是采用 Options API&#xff08;基于选项的 API &#xff09; 来写一个组件的。下面是一个实例&#xff1a; <template> Count is: {{ count }}, doubleCount is: {{ doubleCount…

brpc中http2 grpc协议解析

搭建gRPC服务 | bRPC https://blog.csdn.net/INGNIGHT/article/details/132657099 global.cpp http2_rpc_protocol.cpp ParseH2Message解析frame header信息 ParseResult H2Context::ConsumeFrameHead( 这个是固定长度的9字节帧头部&#xff0c;length是&#xff0c;3*8bit…

七. Django项目之电商购物商城 -- 退出登录

Django项目之电商购物商城 – 退出登录状态 需要开发文档和前端资料的可私聊 退出登录主要是基于Django自带的logout模块 , 该功能只有在登录是保存了用户状态才可以实现调用 一. 创建退出视图 class LogoutView(View):def get(self , request):# 删除用户数据logout(reque…

etcd源码流程---调试环境的搭建

etcd启动命令&#xff1a; name必须设置&#xff0c;否则会用default&#xff0c;集群内不同etcd实例的名字应该是唯一的&#xff0c;因为他会有一个map(name->ip)。如果initial-cluster-state设置为new&#xff0c;那么他会创建一个新的clusterid。需要在initial-cluster中…

PHP 反序列化

一、PHP 序列化 1、对象的序列化 <?php class people{public $nameGaming;private $NationLiyue;protected $Birthday12/22;public function say(){echo "老板你好呀&#xff0c;我是和记厅的镖师&#xff0c;叫我嘉明就行&#xff0c;要运货吗你&#xff1f;"…

【LeetCode:1235. 规划兼职工作 + 动态规划 + 二分查找】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…