Java进阶(6)——抢购问题中的数据不安全(非原子性问题) Java中的synchronize和ReentrantLock锁使用 死锁及其产生的条件
目录
- 引出
- 场景:大量请求拥挤抢购
- 事务的基本特征ACID
- 线程安全的基本特征
- 加锁(java)
- synchronized锁
- ReentrantLock锁
- 什么是可重入锁?
- 如何保证可重入
- 滥用锁的代价?(死锁)
- 死锁的四个必要条件
- 死锁的案例
- 总结
引出
1.大量请求拥挤抢购中的数据不安全问题;
2.事务ACID:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability);
3.线程安全特征:原子性(Atomicity)可见性(Visibility)有序性(Ordering);
4.java中的锁初步,synchronize锁和ReentrantLock锁使用初步;
5.滥用锁的问题,以及产生死锁的条件;
场景:大量请求拥挤抢购
package com.tianju.redis.service.impl;import com.tianju.redis.service.IRushGoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;@Service
public class RushGoodsServiceImpl implements IRushGoodsService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;private final String GOODS = "goods";@Overridepublic String rush() {String sNum = stringRedisTemplate.opsForValue().get(GOODS);int nums = Integer.parseInt(sNum);if (nums>0){stringRedisTemplate.opsForValue().set(GOODS, String.valueOf(--nums) );return stringRedisTemplate.opsForValue().get(GOODS);}else {return "error";}}
}
@PutMapping("/rushJmeter")public void rushJmeter(){String goodsNum = rushGoodsService.rush();System.out.println("goodsNum: "+goodsNum);}
事务的基本特征ACID
事务是指一组操作被视为一个不可分割的工作单元,要么全部执行成功,要么全部不执行。事务具有以下四个基本特征,通常被称为ACID特性:
-
原子性(Atomicity):事务是一个原子操作,要么全部执行成功,要么全部不执行。如果事务中的任何一个操作失败,整个事务将被回滚到初始状态,不会对数据库产生任何影响。
-
一致性(Consistency):事务在执行前和执行后,数据库的状态必须保持一致。这意味着事务中的操作必须满足数据库的完整性约束,包括唯一性约束、外键约束等。
-
隔离性(Isolation):事务的执行是相互隔离的,一个事务的操作不会被其他事务所干扰。隔离性确保了并发执行的事务之间不会产生不一致的结果。
-
持久性(Durability):一旦事务提交成功,其所做的修改将永久保存在数据库中,即使系统发生故障或重启,修改的结果也不会丢失。
这些特性确保了事务的可靠性和一致性。数据库管理系统通过使用日志和锁等机制来实现事务的特性。在设计和实现数据库应用程序时,需要考虑事务的边界和正确使用事务来保证数据的完整性和一致性
线程安全的基本特征
线程安全是指在多线程环境下,对共享资源的访问和操作不会导致数据不一致或产生不可预期的结果。线程安全的基本特征包括:
-
原子性(Atomicity):对共享资源的操作要么全部执行成功,要么全部不执行,不存在中间状态。即使在多线程环境下,也能保证操作的完整性。简单说就是相关操作不会中途被其他线程干扰,一般通过同步机制实现
-
可见性(Visibility):一个线程对共享资源的修改对其他线程是可见的。当一个线程修改了共享资源的值后,其他线程能够立即看到最新的值。可见性,是一个线程修改了某个共享变量,其状态能够立即被其他线程知晓,通常被解释为将线程本地状态反映到主内存上,volatile就是负责保证可见性的。
-
有序性(Ordering):线程的执行顺序与程序的代码顺序一致。即使在多线程环境下,也能保证操作按照预期的顺序执行。是保证线程内串行语义,避免指令重排等。
解决办法
-
使用互斥锁(Mutex)或信号量(Semaphore)等同步机制,确保在同一时间只有一个线程能够访问共享资源。
-
使用原子操作(Atomic Operation)来保证对共享资源的操作是原子的,不会被其他线程中断。
-
使用volatile关键字来保证共享变量的可见性,确保一个线程对共享变量的修改对其他线程是可见的。
-
使用线程安全的数据结构或类,这些数据结构或类已经在设计上考虑了多线程环境下的安全性。
加锁(java)
synchronized锁
可重入锁: sychronized ReentrantLock
synchronized (this.getClass()){}
ReentrantLock锁
private final ReentrantLock lock = new ReentrantLock(); // 可重入锁
什么是可重入锁?
当线程获取某个锁后,还可以继续获取它,可以递归调用,而不会发生死锁;
如何保证可重入
当一个线程访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储偏向的线程ID,以后该线程在进入和退出同步块时不需要进行CAS操作来加锁和解锁,只需简单测试一下对象头的Mark Word里是否存储着指向当前线程的偏向锁。
如果测试成功,表示线程已经获得了锁。
如果测试失败,则需要再测试一下Mark Word中偏向锁标志是否设置成1:没有则CAS竞争;设置了,则CAS将对象头偏向锁指向当前线程。再维护一个计数器,同个线程进入则自增1,离开再减1,直到为0才能释放
滥用锁的代价?(死锁)
死锁的四个必要条件
循环 A —> B —>C —>A
产生死锁的必要条件是以下四个条件同时满足:
-
互斥条件(Mutual Exclusion):至少有一个资源被一个进程独占使用,即在一段时间内只能由一个进程访问。
-
请求与保持条件(Hold and Wait):一个进程在持有至少一个资源的同时,又请求获取其他进程持有的资源。
-
不可剥夺条件(No Preemption):资源只能由持有者显式地释放,其他进程无法强制剥夺。
-
循环等待条件(Circular Wait):存在一个进程资源的循环链,每个进程都在等待下一个进程所持有的资源。
当这四个条件同时满足时,就可能发生死锁。如果任何一个条件不满足,就不会发生死锁。
死锁是多线程或多进程并发执行时的一种常见问题,它会导致系统无法继续执行下去,需要通过死锁检测、死锁预防、死锁避免或死锁解除等方法来处理。
死锁的案例
可能导致死锁
锁对象ObjLock
package com.tianju.redis.lock;public class ObjLock {private String name;public ObjLock(String name){this.name = name;}@Overridepublic String toString() {return "ObjLock:"+this.name;}
}
加锁释放锁方法DeadLockDemo
package com.tianju.redis.lock;public class DeadLockDemo {private ObjLock a;public ObjLock b;public DeadLockDemo(ObjLock a,ObjLock b){this.a = a;this.b = b;}public void dead(){System.out.println("********"+a+"对象"+b+"对象都加锁**************");System.out.println(a+"--"+b+": "+"准备给"+a+"对象加锁>>");synchronized (a){System.out.println(a+"--"+b+": "+a+"对象加锁成功...");System.out.println(a+"--"+b+": "+"准备给"+b+"对象加锁>>>");synchronized (b){System.out.println(a+"--"+b+": "+b+"对象加锁成功");}System.out.println(a+"--"+b+": "+"释放"+b+"对象的锁");}System.out.println(a+"--"+b+": "+"释放"+b+"对象的锁");System.out.println("****************");}
}
测试方法
package com.tianju.redis.lock;public class TestDeadLock {/*** 一个一个顺序运行*/public static void run(){ObjLock a = new ObjLock("A");ObjLock b = new ObjLock("B");ObjLock c = new ObjLock("C");DeadLockDemo lockDemo1 = new DeadLockDemo(a, b);lockDemo1.dead(); // 锁住a和bDeadLockDemo lockDemo2 = new DeadLockDemo(b, c);lockDemo2.dead(); // 锁住a和bDeadLockDemo lockDemo3 = new DeadLockDemo(c, a);lockDemo3.dead(); // 锁住a和b}/*** 进行线程抢,死锁*/public static void rushRun(){ObjLock a = new ObjLock("A");ObjLock b = new ObjLock("B");ObjLock c = new ObjLock("C");new Thread(()->{DeadLockDemo lockDemo1 = new DeadLockDemo(a, b);lockDemo1.dead(); // 锁住a和btry {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();new Thread(()->{DeadLockDemo lockDemo2 = new DeadLockDemo(b, c);lockDemo2.dead(); // 锁住a和btry {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();new Thread(()->{DeadLockDemo lockDemo3 = new DeadLockDemo(c, a);lockDemo3.dead(); // 锁住a和btry {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();}public static void main(String[] args) {
// run(); // 顺序执行加锁,解锁rushRun(); // 线程进行抢}
}
总结
1.大量请求拥挤抢购中的数据不安全问题;
2.事务ACID:原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability);
3.线程安全特征:原子性(Atomicity)可见性(Visibility)有序性(Ordering);
4.java中的锁初步,synchronize锁和ReentrantLock锁使用初步;
5.滥用锁的问题,以及产生死锁的条件;
相关文章:

Java进阶(6)——抢购问题中的数据不安全(非原子性问题) Java中的synchronize和ReentrantLock锁使用 死锁及其产生的条件
目录 引出场景:大量请求拥挤抢购事务的基本特征ACID线程安全的基本特征 加锁(java)synchronized锁ReentrantLock锁什么是可重入锁?如何保证可重入 滥用锁的代价?(死锁)死锁的四个必要条件死锁的案例 总结 引出 1.大量请…...

SpringBoot初级开发--加入Log4j进行日志管理打印(6)
日志记录在整个java工程开发中占着很重要的比重,因为很多问题的排查需要通过日志分析才能确认。在SpringBoot中我用得最多的就是log4j这个日志框架。接下来我们具体配置log4j. log4j定义了8个级别的log(除去OFF和ALL,可以说分为6个级别&#…...

计算机竞赛 基于GRU的 电影评论情感分析 - python 深度学习 情感分类
文章目录 1 前言1.1 项目介绍 2 情感分类介绍3 数据集4 实现4.1 数据预处理4.2 构建网络4.3 训练模型4.4 模型评估4.5 模型预测 5 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 基于GRU的 电影评论情感分析 该项目较为新颖,适合作为竞…...

android logcat问题 怎么换成旧版
参考 如果想切换回旧版LOGCAT,按照下方步骤设置即可 File->Settings->Expermental->Logcat->Enable new Logcat tool window:取消勾选 设置好后上方会有一个Toast,询问你是否使用新版logcat,关掉即可 最新测试版移…...
监听的用法watch
1、当想停止某页面定时刷新(监听路由的变化) /**组件被移除时调用 */deactivated() {clearInterval(this.timer);this.timer null;},/**监听路由变化是否刷新 */watch: {// 方法1 //监听路由是否变化$route(to, from) {if (to.name "xxx") {…...

XML—标记语言
什么是XML? Extensible Markup Language,可扩展标记语言。 那标记语言是什么? 用文字做标记表达一些效果或携带一些数据。比如:HTML、XML 我的理解:用倾盆大雨表达雨很大 那XML为什么说是可扩展的呢? 还…...

图数据库Neo4j学习五渲染图数据库neo4jd3
文章目录 1.现成的工具2.Neo4j JavaScript Driver3.neovis4.neo4jd34.1neo4jd3和neovis对比4.2获取neo4jd34.3neo4jd3的数据结构4.4Spring data neo4.4.1 定义返回数据格式4.4.1.1NeoResults4.4.1.2GraphVO4.4.1.3NodeVO4.4.1.4ShipVO 4.4.2 SDN查询解析4.4.2.1 Repo查询语句4.…...

AI增强的社交网络·导师·电话客服……
本月共更新80条知识, 智能时代,人与人之间的差距,体现在前沿知识的整合上。 # BeFake AI AI-augmented social network AI增强的社交网络,用户使用文本提示来生成图像,拍摄自己的“AI”版本。任何人都可以创建全新的虚…...
c# Task异步使用
描述 Task出现之前,微软的多线程处理方式有:Thread→ThreadPool→委托的异步调用,虽然可以满足基本业务场景,但它们在多个线程的等待处理方面、资源占用方面、延续和阻塞方面都显得比较笨拙,在面对复杂的业务场景下&am…...
QuickLook概述和使用以及常用插件
1、QuickLook概述 QuickLook: 是可以快速预览的工具,开源、免费。通过空格键即可快速查看文件内容。 文件无需打开就可以用QuickLook一键快速预览。 说明文档:https://en.wikipedia.org/wiki/Quick_Look github地址:https://git…...

1A快恢复整流二极管型号汇总
快恢复整流二极管是二极管中的一种,开关特性好、反向恢复时间短,在开关电源、PWM脉宽调制器、变频器等电子电路中经常能看到它的身影。快恢复整流二极管的内部结构与普通PN结二极管不同,它属于PIN结型二极管,即在P型硅材料与N型硅…...

【element-ui】el-dialog改变宽度
dialog默认宽度为父元素的50%,这就导致在移动端会非常的窄,如图1,需要限定宽度。 解决方法:添加custom-class属性,然后在style中编写样式,注意,如果有scoped限定,需要加::v-deep &l…...
第三讲,实践编程 Eigen
目录 1.实践 Eigen1.1 Eigen的简介1.2 Eigen 向量和矩阵的 声明1.3 Eigen的输出操作1.4 矩阵和向量相乘 要注意数据类型 矩阵纬度1.5 矩阵的四则运算1.6 矩阵求解特征向量和特征值1.7 解方程 求逆 1.实践 Eigen 1.1 Eigen的简介 Eigen是一个 C 开源线性代数库。它提供了快…...

POI实现百万数据导出
1、概述 我们都知道Excel可以分为早期的Excel2003版本(使用POI的HSSF对象操作)和Excel2007版本(使用POI的XSSF操作),两者对百万数据的支持如下: Excel 2003:在POI中使用HSSF对象时&#…...

如何制作党建专题汇报片
通过展示党组织的凝聚力和战斗力,增强党员的组织归属感和团结合作意识。通过宣传片,可以加强党组织的凝聚力,推动党的事业发展。制作党建专题汇报片需要一定的前期准备和后期制作技巧。下面是由深圳党建专题汇报片制作公司老友记小编为您整理…...

沉浸式VR虚拟实景样板间降低了看房购房的难度
720 全景是一种以全景视角为特点的虚拟现实展示方式,它通过全景图像和虚拟现实技术,将用户带入一个仿佛置身其中的沉浸式体验中。720 全景可以应用于旅游、房地产、展览等多个领域,为用户提供更为直观、真实的体验。 在房地产领域,…...
如何在Linux环境下给Web应用配置HTTPS证书
如何在Linux环境下给Web应用配置HTTPS证书 在当今互联网时代,保护用户数据的安全性至关重要。为你的Web应用启用HTTPS协议是确保数据传输加密和身份验证的一种有效方式。本文将指导你如何在Linux环境下为Web应用程序配置HTTPS证书。 1. 获取SSL证书 首先…...

面试题-React(七):React组件通信
在React开发中,组件通信是一个核心概念,它使得不同组件能够协同工作,实现更复杂的交互和数据传递。常见的组件通信方式:父传子和子传父 一、父传子通信方式 父组件向子组件传递数据是React中最常见的一种通信方式。这种方式适用…...

MASM32编程调用 API函数RtlIpv6AddressToString,Windows 10 容易,Windows 7 折腾
一、需求分析 最近用MASM32编程更新SysInfo,增加对IPv6连接信息的收集功能,其中涉及到 MIB_TCP6ROW_OWNER_MODULE 结构体: ;typedef struct _MIB_TCP6ROW_OWNER_MODULE { ; UCHAR ucLocalAddr[16]; ; DWORD dwLocalScope…...

为什么使用Nacos而不是Eureka(Nacos和Eureka的区别)
文章目录 前言一、Eureka是什么?二、Nacos是什么?三、Nacos和Eureka的区别3.1 支持的CAP3.2连接方式3.3 服务异常剔除3.4 操作实例方式 总结 前言 为什么如今微服务注册中心用Nacos相对比用Eureka的多了?本文章将介绍他们之间的区别和优缺点…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
渲染学进阶内容——模型
最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...

uni-app学习笔记三十五--扩展组件的安装和使用
由于内置组件不能满足日常开发需要,uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件,需要安装才能使用。 一、安装扩展插件 安装方法: 1.访问uniapp官方文档组件部分:组件使用的入门教程 | uni-app官网 点击左侧…...