JAVAEE——多线程进阶,锁策略
文章目录
- 锁策略
- 乐观锁和悲观锁
- 乐观锁
- 悲观锁
- 两者的比较
- 读写锁
- 重量级锁和轻量级锁
- 重量级锁
- 轻量级锁
- 自旋锁
- 公平锁和非公平锁
- 公平锁
- 非公平锁
- 可重入锁和不可重入锁
- 可重入锁
- 不可重入锁
锁策略
乐观锁和悲观锁
乐观锁
什么是乐观锁呢?我们可以认为乐观锁比较自信,当多线程执行的时候如果要对一个资源进行访问,那么乐观锁会认为这些线程的访问是不会造成冲突的,并且这些访问也不都是要进行修改。因此对这些线程访问更新的时候乐观锁才会进行检测查看这个进程的访问是否会造成冲突,如果会的话就返回错误信息由用户决定是否如何去做
悲观锁
悲观锁相较于乐观锁也是一种极端,悲观锁认为只要访问就一定会造成并发冲突,因此悲观锁认为只要是访问资源,都必须加上锁,这样当别人想要获取这个资源的时候就必须获取这把锁陷入了阻塞等待当中。
两者的比较
这里我们举一个例子来说明
假如说甲乙两位同学向老师请问问题,那么甲是一个悲观的人,乙是一个乐观的人,甲突然去找老师,老师肯定在忙碌无法给自己将题目,因此会先给老师发个消息询问老师是否在忙碌当得到老师的答复之后再决定是继续等待还是直接过去,而乙则是比较乐观,认为自己现在过去不会打扰到老师,老师可以立即解答自己的疑惑,因此乙就会直接过去询问老师问题,这时候可能老师确实没有忙碌可以直接解决问题也有可能老师是在忙碌的,这时候乙就需要进行等待了。
结论:两把锁各有特点针对于不同的场合使用不同的锁没有什么优劣性比较。
读写锁
读写锁。线程对一个资源的访问是分为读操作和写操作的,那么对于一个资源来说读操作是不会导致线程不安全的只有写操作才会导致线程不安全,因此线程对一个资源的访问加锁我们也可以分为读锁和写锁来进行,因此我们就需要搞明白哪些情况会导致线程不安全
- 线程同时去读取一个数据:安全的
- 一批线程去读另一批线程在写:不安全
- 线程都在写:不安全
因此读写锁,也就诞生了,那么读写锁是怎么进行加锁的呢?按照字面意思肯定就是按照一个线程是读还是写来区别加锁了。那么既然是按照意图来进行区别加锁的我们首先当然要清除这个线程想要进行的操作是什么才可以来进行加锁。也就是加锁前需要获取这个线程的行为意图。
读写锁就是把读操作和写操作区分对待. Java 标准库提供了 ReentrantReadWriteLock 类, 实现了读写
锁.
我们来写一个示例代码运行一下查看
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class Lock_policy {public static int tmp=10;public static final ReentrantReadWriteLock wrlock=new ReentrantReadWriteLock();public static void main(String[] args) {Thread t1=new Thread(()->{wrlock.readLock().lock();System.out.println("我是t1线程"+tmp);//wrlock.readLock().unlock();});Thread t2=new Thread(()->{wrlock.readLock().lock();System.out.println("我是t2线程"+tmp);//wrlock.readLock().unlock();});Thread t3=new Thread(()->{wrlock.writeLock().lock();tmp++;System.out.println("我是t3线程"+tmp);});t1.start();t2.start();}
}
首先我们可以观察到这个代码中我们创建的t3线程并没有start运行因此我们测试的是当两个线程同时加上读锁并且读一个数据的时候是否会阻塞我们看一下运行结果。
结果很明显程序正常跑完因此没有任何的阻塞。我们来试试把t3线程运行试试结果。
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class Lock_policy {public static int tmp=10;public static final ReentrantReadWriteLock wrlock=new ReentrantReadWriteLock();public static void main(String[] args) {Thread t1=new Thread(()->{wrlock.readLock().lock();System.out.println("我是t1线程"+tmp);//wrlock.readLock().unlock();});Thread t2=new Thread(()->{wrlock.readLock().lock();System.out.println("我是t2线程"+tmp);//wrlock.readLock().unlock();});Thread t3=new Thread(()->{wrlock.writeLock().lock();tmp++;System.out.println("我是t3线程"+tmp);});t1.start();t2.start();t3.start();}
}
运行截图如下
那么是否只有这一种结果呢?当然不是。
在实验的过程中我们可能产生这些不同的结果那么这是为什么呢?原因很简单那就是因为t3线程在t1和t2线程获取读锁之前就已经加上了写锁导致了t1和t2的读操作阻塞了。那么无论上述的哪种 结果都是可以说明读写锁中读锁和写锁是阻塞的。
重量级锁和轻量级锁
重量级锁
在理解这里的时候我们要先搞明白什么是重量级锁。顾名思义听名字就感觉这个锁很慢,那么这种原因究竟是为什么呢?这就要追溯到锁的一个机制了。
我们要搞明白加锁是为了干什么?很简单加锁是为了保证我们的多个操作是原子性的。原子性的保证使得我们的操作避免了多线程的安全问题。那么为什么锁可以保证操作的原子性呢?其实说白了还是因为我们的硬件设备的支持也就是底层建筑决定上层建筑,因为我们的硬件支持,所以我们的操作系统可以给我们提供一系列的锁的操作接口,而操作系统提供的接口就是mutex。
- CPU 提供了 “原子操作指令”.
- 操作系统基于 CPU 的原子指令, 实现了 mutex 互斥锁.
- JVM 基于操作系统提供的互斥锁, 实现了 synchronized 和 ReentrantLock 等关键字和类
重量级锁:加锁机制非常依赖于OS提供的mutex因此在加锁的时候涉及到大量的从内核态到用户态的转变,效率较低。
轻量级锁
轻量级锁即加锁的时候尽量不依赖于mutex而是尽量在用户态代码完成. 实在搞不定了, 再使用 mutex。那么这时候有些美女或者帅哥可能就会很混乱,说的直白一些就是,轻量级锁就是尽量不去调用系统接口他就是一个优化。
自旋锁
什么是自旋锁呢?那么按照我们之前写的代码当我们的锁被抢占的时候如果我们也想抢占这把锁的话就需要先进行阻塞等待也就是wait然后等待被唤醒,可是我们不希望这样怎么办?也就是说可能当前占有锁的这个进程很快就结束了就要释放这把锁了
公平锁和非公平锁
公平锁
公平锁遵守先来后到的原则B比C先来的那么当A释放锁之后B就会比C先获取到释放的锁
非公平锁
不遵守先来后到的原则,synchronized()就是一个非公平锁,他的调度顺序是有操作系统决定的。
- 操作系统内部的线程调度就可以视为是随机的. 如果不做任何额外的限制, 锁就是非公平锁. 如果要
想实现公平锁, 就需要依赖额外的数据结构, 来记录线程们的先后顺序.- 公平锁和非公平锁没有好坏之分, 关键还是看适用场景.
可重入锁和不可重入锁
可重入锁
可重入的意思就是同一个线程可以多次获取同一把锁。也就是可以重新进入的锁。synchorinzed就是一把可重入锁。Java里只要以Reentrant开头命名的锁都是可重入锁,而且JDK提供的所有现成的Lock实现类,包括
synchronized关键字锁都是可重入的。
不可重入锁
不可重入锁就是当自己这个线程要重新申请这把锁的时候要进行等待便是不可重入锁。
相关文章:

JAVAEE——多线程进阶,锁策略
文章目录 锁策略乐观锁和悲观锁乐观锁悲观锁两者的比较 读写锁重量级锁和轻量级锁重量级锁轻量级锁 自旋锁公平锁和非公平锁公平锁非公平锁 可重入锁和不可重入锁可重入锁不可重入锁 锁策略 乐观锁和悲观锁 乐观锁 什么是乐观锁呢?我们可以认为乐观锁比较自信&am…...
富文本编辑器Quill全套教程
Quill简介 Quill是一款现代的富文本编辑器,它以其API驱动的设计和对文本格式的深度理解而著称。与传统的富文本编辑器不同,Quill专注于以字符为中心,构建了一个直观且易于使用的API,使得开发者能够轻松地对文本进行格式化和编辑。…...
Swift 代码注释的使用
Swift代码注释的使用 在 iOS 开发中,代码注释是一种很好的实践,可以帮助他人更容易理解你的代码。通常可以在代码中使用注释来解释代码的功能、目的、实现细节等。下面是一些常见的 iOS 代码注释示例: 1. 单行注释: // 这是一个…...

蓝桥杯—DS1302
目录 1.管脚 2.时序&官方提供的读写函数 3.如何使用读写函数 4.如何在数码管中显示在DS1302中读取出的数据? 1.管脚 2.时序&官方提供的读写函数 /* # DS1302代码片段说明1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。2. 参赛选手可以自行…...
nginx: 集群环境配置搭建
nginx 集群环境搭建 1 ) 概述 nginx 本身就应该选择性能强劲的机器同时为了满足更多流量的需求, 多台nginx 机器做集群来满足强大的需求故而,我们需要一个负载均衡器,以及多台nginx的机器 这里负载均衡器应该有主从和热备,目前先使用一台来描…...

Linux:进程终止和等待
一、进程终止 main函数的返回值也叫做进程的退出码,一般0表示成功,非零表示失败。我们也可以用不同的数字来表示不同失败的原因。 echo $?//打印最近一次进程执行的退出码 而作为程序猿,我们更需要知道的是错误码所代表的错误信息&#x…...

一、next-auth 身份验证凭据-使用电子邮件和密码注册登录
一、next-auth 身份验证凭据-使用电子邮件和密码注册登录 文章目录 一、next-auth 身份验证凭据-使用电子邮件和密码注册登录一、前言二、前置准备1、环境配置2、相关库安装(1)vercel 配置(2)Yarn 包管理配置 3、next项目初始化与…...

2.SpringBoot利用Thymeleaf实现页面的展示
什么是Thymeleaf? Thymeleaf是一个现代服务器端Java模板引擎,适用于Web和独立环境,能够处理HTML,XML,JavaScript,CSS甚至纯文本。 Thymeleaf的主要目标是提供一种优雅且高度可维护的模板创建方式。为实现这…...
devtool: ‘source-map‘ 和 devtool: ‘#source-map‘的区别
devtool: ‘source-map’ 和 devtool: ‘#source-map’ 之间的区别主要在于前面的#字符。 从Webpack 4开始,就废弃了在devtool选项前加#的用法。 devtool: ‘source-map’ 选项意味着Webpack在构建过程中会生成独立的完整的source map文件。对于测试环境很有用&…...

Flutter Boost 3
社区的 issue 没有收敛的趋势。 设计过于复杂,概念太多。这让一个新手看 FlutterBoost 的代码很吃力。 这些问题促使我们重新梳理设计,为了彻底解决这些顽固的问题,我们做一次大升级,我们把这次升级命名为 FlutterBoost 3.0&am…...
ElementUI响应式Layout布局xs,sm,md,lg,xl
响应式布局 参照了 Bootstrap 的 响应式设计,预设了五个响应尺寸:xs、sm、md、lg 和 xl。 <el-row :gutter"10"><el-col :xs"8" :sm"6" :md"4" :lg"3" :xl"1"><div class…...
机器学习——典型的卷积神经网络
机器学习——典型的卷积神经网络 卷积神经网络(Convolutional Neural Networks,CNNs)是一类在图像处理领域应用广泛的深度学习模型。它通过卷积操作和池化操作来提取图像的特征,并通过全连接层来进行分类或回归任务。在本文中&am…...

速通数据结构与算法第四站 双链表
系列文章目录 速通数据结构与算法系列 1 速通数据结构与算法第一站 复杂度 http://t.csdnimg.cn/sxEGF 2 速通数据结构与算法第二站 顺序表 http://t.csdnimg.cn/WVyDb 3 速通数据结构与算法第三站 单链表 http://t.csdnimg.cn/cDpcC 感谢佬们…...

51单片机学习笔记12 SPI接口 使用1302时钟
51单片机学习笔记12 SPI接口 使用1302时钟 一、DS1302简介1. 功能特性2. 涓流充电3. 接口介绍时钟数据和控制线:电源线:备用电池连接: 二、寄存器介绍1. 控制寄存器2. 时间寄存器3. 日历/时钟寄存器 三、BCD码介绍四、DS1302时序1. 读时序2. …...
php编辑器 ide 主流编辑器的优缺点。phpstorm vscode atom 三者对比
编辑器PhpStormvscodeAtom是否收费收费,有30天试用期免费免费内存占用Java平台,一个进程1G多内存占用好几个进程,合起来1G上下/基本功能都具备,有的功能需要装插件都具备,有的功能需要装插件都具备,有的功能…...

【动手学深度学习】深入浅出深度学习之RMSProp算法的设计与实现
目录 🌞一、实验目的 🌞二、实验准备 🌞三、实验内容 🌼1. 认识RMSProp算法 🌼2. 在optimizer_compare_naive.py中加入RMSProp 🌼3. 在optimizer_compare_mnist.py中加入RMSProp 🌼4. 问…...

大转盘抽奖小程序源码
源码介绍 大转盘抽奖小程序源码,测试依旧可用,无BUG,跑马灯旋转效果,非常酷炫。 小程序核心代码参考 //index.js //获取应用实例 var app getApp() Page({data: {circleList: [],//圆点数组awardList: [],//奖品数组colorCirc…...
数据结构(无图版)
数据结构与算法(无图版,C语言实现) 1、绪论 1.1、数据结构的研究内容 一般应用步骤:分析问题,提取操作对象,分析操作对象之间的关系,建立数学模型。 1.2、基本概念和术语 数据:…...

软件测试中的顶级测试覆盖率技术
根据 CISQ 报告,劣质软件每年给美国公司造成约2.08 万亿美元的损失。虽然软件工具是企业和行业领域的必需品,但它们也容易出现严重错误和性能问题。人类手动测试不再足以检测和消除软件错误。 因此,产品或软件开发公司必须转向自动化测试&am…...
vscode使用技巧
常用快捷键 代码格式 Windows系统。格式化代码的快捷键是“ShiftAltF” Mac系统。格式化代码的快捷键是“ShiftOptionF” Ubuntu系统。格式化代码的快捷键是“CtrlShiftI”配置缩进 点击左上角的“文件”菜单,然后选择“首选项”>“设置”,或者使用…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...