[JAVAEE] 线程安全问题

news2024/11/26 3:51:09

目录

一. 什么是线程安全

二. 线程安全问题产生的原因

三. 线程安全问题的解决

3.1 解决修改操作不是原子性的问题 => 加锁

a. 什么是锁

b.  没有加锁时

c. 加锁时 

d. 死锁

e. 避免死锁 

3.2 解决内存可见性的问题 => volatile关键字 (易变的, 善变的)

a. 不加volatile关键字

b. 加volatile关键字

四. 等待和通知

4.1 wait() 和 nitify()

  五. 总结


一. 什么是线程安全

在多线程并发执行的过程中, 出现 bug, 称为线程不安全. 反之则线程安全.


二. 线程安全问题产生的原因

1. 操作系统对于线程的调度是随机的, 抢占式的[根本原因].

2. 多个线程修改同一个变量.

3. 修改操作不是原子的. => 解决: 锁

4. 内存可见性. => 解决: volatile(adj. 善变的. 易变的)关键字, 表示当前变量不会被编译器+jvm优化存储到寄存器中, 而是始终存在于内存中.

5. 指令重排序. => 解决: volatile关键字, 表示当前变量不允许指令重排序


三. 线程安全问题的解决

3.1 解决修改操作不是原子性的问题 => 加锁

a. 什么是锁

synchronized修饰普通方法, 是对this加锁.

synchronized修饰静态方法, 是对类对象加锁. 

b.  没有加锁时

没有对count++操作进行加锁时, count的结果总是 <= 100000, 这是因为(线程调度是随机的, 抢占式的 + count++操作不是原子的)

c. 加锁时 

对count++操作进行加锁后, count++操作可以认为变成原子的了, 这时, count的最终结果就符合预期.

d. 死锁

构成死锁的场景:

1. 一个线程, 一把锁 (但是, java中锁具有可重入特性, 此种情况下, 并不会构成死锁)

2. 两个线程, 两把锁

3. n个线程, m把锁 

构成死锁的四个必要条件:

1. 锁是互斥的. (线程1获取了锁1, 这时线程2想要再获取锁1 就要阻塞等待)

2. 锁是不可抢占的

3. 请求和保持. (线程1获取了锁1, 线程2获取了锁2, 此时, 线程1想要再获取锁2, 线程2想要再获取锁1, 这时就会构成死锁, 线程阻塞) => 解决: 一定情况下, 避免嵌套

4. 循环等待. => 解决: 约定加锁的顺序.

e. 避免死锁 

想要避免死锁, 就要解决 3 或者 4 这两个必要条件.

解决3. (避免嵌套)

解决4.(按照一定的顺序进行加锁)

3.2 解决内存可见性的问题 => volatile关键字 (易变的, 善变的)

a. 不加volatile关键字

 

可以观察到, t1线程并没有因为t2线程输入val的值不是0而结束, 反而一直在RUNNABLE(运行中). 这是因为, jvm和编译器对代码进行了优化, jvm检测到val的值一直不发生改变, 为了提高效率, 就把val转移到了寄存器中, 此时t2线程输入val还在和内存进行交互, 并不会改变val的值.

b. 加volatile关键字

加上volatile关键字, 表示val的值是易变的, 用户随时可能会修改, 此时, jvm和编译器就不会对val的存储进行优化, val一直存在于内存中.

3.3 解决指令重排序的问题 => volatile关键字


四. 等待和通知

wait() 和 notify() 都是Object类中的方法.

wait() 和 notify() 都需要在加锁状态下使用, 先wait()再notify().

4.1 wait() 和 nitify()

locker1.wait(): 表示当前线程先释放锁, 此时锁可以被其他线程获取(避免线程饿死), 并且当前线程阻塞, 等待被通知.

locker1.notify(): 通知正在阻塞等待的线程可以获取锁了, 并且此时阻塞线程结束等待.

注意: 使用wait和notify之前当前线程都需要获取锁.

 


  五. 总结

1. 线程安全问题产生的原因.

2. 如何解决线程安全问题

(原子性 => 锁(注意避免死锁)

内存可见性 => volatile关键字 => 不让编译器和jvm对变量存储进行优化

指令重排序 => volatile关键字 => 添加volatile的变量不支持指令重排序)

3. wait和notify方法

(wait(): 当前线程释放锁, 此时其他线程可以获取锁, 避免线程饿死, 并且当前线程阻塞, 等待通知.

notify(): 表示阻塞等待的线程可以获取锁, 并且等待的线程结束阻塞状态)

(注意: wait和notify之前需要进行加锁)

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

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

相关文章

【Linux】多线程安全之道:互斥、加锁技术与底层原理

目录 1.线程的互斥 1.1.进程线程间的互斥相关背景概念 1.2.互斥量mutex的基本概念 所以多线程之间为什么要有互斥&#xff1f; 为什么抢票会抢到负数&#xff0c;无法获得正确结果&#xff1f; 为什么--操作不是原子性的呢&#xff1f; 解决方式&#xff1a; 2.三种加锁…

git add操作,文件数量太多卡咋办呢,

git add介绍 Git的add命令是用于将文件或目录添加到暂存区&#xff08;也就是索引库&#xff09;&#xff0c;以便在后续的提交&#xff08;commit&#xff09;操作中一并上传到版本库的。具体来说&#xff0c;git add命令有以下几种常见用法&#xff1a; 添加单个文件&#…

4、.Net 快速开发框架:DncZeus - 开源项目研究文章

DncZeus 是一个基于 ASP.NET Core 和 Vue.js 的前后端分离的通用后台管理系统框架&#xff0c;其愿景是成为一个易于使用且功能丰富的 .NET Core 通用后台权限管理模板系统基础框架。项目名称 "DncZeus" 由 "Dnc"(.NET Core 的缩写)和 "Zeus"(古…

CLion和Qt 联合开发环境配置教程(Windows和Linux版)

需要安装的工具CLion 和Qt CLion下载链接 :https://www.jetbrains.com.cn/clion/ 这个软件属于直接默认安装就行&#xff0c;很简单&#xff0c;不多做介绍了 Qt:https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/online_installers/ window 直接点exe Linux 先c…

el-table动态新增/删除表单行及校验规则

方式一&#xff1a; <template><el-form ref"ruleFormRef" :model"ruleForm" :rules"rules" label-width"120px" class"model-ruleForm":size"formSize" status-icon label-position"top">…

堆的使用实例

小伙伴们大家好&#xff0c;今天为大家带来一道算法题&#xff1a; 分析题意我们可知&#xff1a;数组最小元素一定位于0~k位置&#xff0c;如果我们首先将0~k位置构成最小堆&#xff0c;那么堆顶一定就是数组最小值。将堆顶拿出&#xff0c;将数组k1位置放入&#xff0c;那么数…

无人机+视频推流直播EasyCVR视频汇聚/EasyDSS平台在森林防护巡检中的解决方案

随着科技的飞速发展&#xff0c;无人机技术在各个领域的应用日益广泛&#xff0c;特别是在森林防护与巡检方面&#xff0c;无人机以其独特的优势&#xff0c;为传统林业管理带来了革命性的变化。本文将探讨无人机在森林防护巡检中的解决方案&#xff0c;分析其工作原理、优势及…

MYSQL 拼接函数

目录 1、CONCAT 2、CONCAT_WS 1、CONCAT 解释&#xff1a;用于拼接两个或多个字符串成一个字符串。如果任何一个参数为 NULL&#xff0c;则 CONCAT 函数的结果也会是 NULL。 语法格式&#xff1a;SELECT concat(column_name1,column_name2,...) FROM table_name 中文注释&…

【verilog刷题】时钟切换电路

时钟切换电路 1.基本概念-相关时钟源和无关时钟源2.基本的时钟切换电路&#xff08;组合逻辑&#xff09;2.相关时钟源无毛刺时钟切换电路3.非相关时钟源无毛刺时钟切换电路 1.基本概念-相关时钟源和无关时钟源 相关时钟源&#xff1a;时钟信号源之间存在某种同步或关联的关系…

[含文档+PPT+源码等]精品基于Nodejs实现的医院问诊系统的设计与实现

基于Node.js实现的医院问诊系统的设计与实现背景主要源于以下几个方面&#xff1a; 一、医疗行业变革的需求 随着互联网的飞速发展&#xff0c;特别是移动互联网技术的广泛应用&#xff0c;传统医疗行业正经历着前所未有的变革。医疗资源分布不均、患者就医难等问题日益凸显&…

数据结构单向链表的插入和删除(一)

链表 一、链表结构&#xff1a; &#xff08;物理存储结构上不连续&#xff0c;逻辑上连续&#xff1b;大小不固定&#xff09;二、单链表&#xff1a;三、单项链表的代码实现&#xff1a;四、开发可用的链表&#xff1a;四、单链表的效率分析&#xff1a; 一、链表结构&#x…

爬虫结合项目实战

由于本人是大数据专业&#xff0c;所以准备的是使用pycharm工具进行爬虫爬取数据&#xff0c;然后实现一个可视化大屏 参考项目&#xff1a; 1.医院大数据可视化最后展示 2. 大数据分析可视化系统展示 代码包&#xff1a;

如何防止SpringBoot中的jar反编译?解决相关报错及踩到的坑

目录 1. 面对的场景 2. 方案 2.1 使用代码混淆 2.2 JAR包加密 3. 项目操作 4. 启动方式 5. 踩到的各种坑 5.1 java -jar xxx-0.0.1-SNAPSHOT.jar 没有主清单属性 5.2 Caused by: java.lang.IllegalArgumentException: Unrecognized option: -pwdfxw-jar 1. 面对的场景…

sql-labs靶场第十七关测试报告

目录 一、测试环境 1、系统环境 2、使用工具/软件 二、测试目的 三、操作过程 1、寻找注入点 2、注入数据库 ①寻找注入方法 ②爆库&#xff0c;查看数据库名称 ③爆表&#xff0c;查看security库的所有表 ④爆列&#xff0c;查看users表的所有列 ⑤成功获取用户名…

STM32CubeMX【串口收发USART】

第一步&#xff0c;配置cubemx 配置好点右上角生成 第二步&#xff0c;串口方式 阻塞式发送 英文、中文正常、浮点有口 /* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();//配置完自动生成的 发送到串口助手上 while (1){/* USER CODE…

【计算机网络 - 基础问题】每日 3 题(五十)

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞…

有限状态机和抽象类多态

学习有限状态机的写法&#xff0c;我们会用一个抽象类继承的方法来写 首先&#xff0c;现在我们已经用过类的继承了&#xff0c;就是在我们敌人和野猪的这个代码当中&#xff0c; 我们打开野猪的代码&#xff0c;它继承了Enemy这个父类&#xff0c;所以可以遗传它父类当中所有…

线性代数基础02

目录 1.向量 1.1向量的定义 1.2向量的运算 1.2.1向量加法 1.2.2向量数乘 1.2.3向量点积 1.3矩阵的特征值和特征向量 1.4向量的模 1.4.1向量的模的定义 1.4.2向量的模的几何解释 1.4.3向量的模的性质 1.5向量的内积 1.5.1向量的内积的定义 1.5.2向量的内积的几何解…

【Linux】进程概念 PCB结构体 fork创建子进程

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 每日小感慨&#xff…

UDP/TCP协议详解

目录 一,自定义应用层协议: 1)xml 2),JSON 3),yml 4),google protobuffer 二,传输层UDP/TCP: UDP协议: TCP协议: TCP的核心机制一:确认应答 TCP核心机制二:超时重传 TCP核心机制三:连接管理 TCP核心机制四:滑动窗口 TCP核心机制五:流量控制 TCP核心机制六:拥塞控制…