[JAVAEE] 线程安全问题

目录

一. 什么是线程安全

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

三. 线程安全问题的解决

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之前需要进行加锁)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ string的精讲

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 前言 string是标准库中的一个类&#xff0c;它位于<string>头文件中。这个类提供…

Python算法——链表(反转链表,合并两个排序链表,判断是否有环,链表中倒数最后k个结点,第一个公共结点,删除重复元素)

哈喽大家好&#xff0c;好久不见&#xff01;又进入新的一个学期&#xff0c;这学期小编要进行python的算法学习啦&#xff0c;今天更新链表的部分题目~ 牛客 NC78 反转链表 题目如下&#xff1a; 算法思想如下&#xff1a; 1.初始化两个指针pre和cur&#xff0c;分别表示前驱…

ERROR [internal] load metadata for docker.io/library/nginx:latest

docker执行错误解决方法 1、执行docker pull nginx2、docker build -t xxx:xx

Ai环境安装教程

依赖的驱动软件 python3.115cuda11.4torch2.0.1 一。如何下载安装 一、驱动下载 【Python链接】https://www.python.org/ftp/python/3.11.5/python-3.11.5-amd64.exe 【CUDA链接】https://developer.download.nvidia.com/compute/cuda/11.4.4/local_installers/cuda_11.4.4…

从 Microsoft 官网下载 Windows 10

方法一&#xff1a; 打开 Microsoft 官网&#xff1a; 打开开发人员工具&#xff08;按 F12 或右键点击“检查”&#xff09;。 点击“电脑模拟手机”按钮&#xff0c;即下图&#xff1a; 点击后重新加载此网页&#xff0c;即可看到下载选项。

成都睿明智科技有限公司共创抖音电商新篇章

在当今这个数字化浪潮汹涌的时代&#xff0c;抖音电商以其独特的魅力迅速崛起&#xff0c;成为众多商家竞相追逐的新蓝海。在这片充满机遇与挑战的领域中&#xff0c;成都睿明智科技有限公司凭借其专业的服务、创新的策略和敏锐的市场洞察力&#xff0c;成为了众多商家信赖的合…

Notepad++将搜索内容所在行选中,并进行复制等操作

背景 Notepad在非常多的数据行内容中&#xff0c;按照指定内容检索&#xff0c;并定位到具体行&#xff0c;而后对内容行的数据进行复制、剪切、删除等处理动作。 操作说明 检索并标记所在行 弹出搜索框&#xff1a;按下 Ctrl F。 输入查找字符串&#xff1a;在搜索框中输入要…

房屋租赁管理系统|基于java和小程序的房屋租赁管理系统小程序设计与实现(源码+数据库+文档)

房屋租赁管理系统小程序 目录 基于java和小程序的房屋租赁管理系统小程序设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设…

java项目之精准扶贫管理系统源码(springboot+mysql+vue)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的精准扶贫管理系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 精准扶贫管理系统的主要…

STM32重拾+找工作MD

1.工程文件创建 外部的文件夹要和工程文件对应&#xff0c;也就是外面创建好之后&#xff0c;里面也要对应添加&#xff1b; 首先是startup启动文件&#xff0c;这个是程序执行最基本的文件&#xff0c;keil中启动文件是用汇编写的&#xff0c;启动文件内定义了中断向量表&…

Java面试指南:Java基础介绍

这是《Java面试指南》系列的第1篇&#xff0c;本篇主要是介绍Java的一些基础内容&#xff1a; 1、Java语言的起源 2、Java EE、Java SE、Java ME介绍 3、Java语言的特点 4、Java和C的区别和联系&#xff1f; 5、面向对象和面向过程的比较 6、Java面向对象的三大特性&#xff1a…

GitLab 老旧版本如何升级?

极狐GitLab 正式对外推出 GitLab 专业升级服务 https://dl.gitlab.cn/cm33bsfv&#xff01; 专业的技术人员为您的 GitLab 老旧版本实例进行专业升级&#xff01;服务详情可以在官网查看详细解读&#xff01; 那些因为老旧版本而被攻击的例子 话不多说&#xff0c;直接上图&a…

QT实现校园导航

导航是地图类项目实战中经常会遇到了。看上去貌似没头绪&#xff0c;其实是有模板遵循的。我们直接根据图看代码。 //MainWidget.h#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include "mapwidget.h" #include <QToolButton> #in…

比较相同机器上 redis和mysql分别单独承载的 最大连接数量

在相同的机器上&#xff0c;Redis 和 MySQL 的最大连接数量会受到硬件配置&#xff08;如 CPU、内存、网络等&#xff09;、配置参数和应用场景的影响。以下是对 Redis 和 MySQL 在单机环境下最大连接数的比较&#xff1a; Redis 最大连接数量 默认配置&#xff1a; Redis 默…

【动手学深度学习】7.3 网络中的网络(NiN)(个人向笔记)

LeNet&#xff0c;AlexNet和VGG都有一个共同的设计模型&#xff1a;通过一系列卷积层和汇聚层来提取空间结构特征&#xff0c;然后通过全连接层对特征的表征进行处理AlexNet和VGG对LeNet的改进主要是在于如何扩大和加深这两个模块网络中的网络(NIN)提出了&#xff1a;在每个像素…

视频云存储/音视频流媒体视频平台EasyCVR视频汇聚平台在欧拉系统中启动失败是什么原因?

视频监控/视频集中存储/磁盘阵列EasyCVR视频汇聚平台具备强大的拓展性和灵活性&#xff0c;支持多种视频流的外部分发&#xff0c;如RTMP、RTSP、HTTP-FLV、WebSocket-FLV、HLS、WebRTC、fmp4等&#xff0c;这为其在各种复杂环境下的部署提供了便利。 安防监控EasyCVR视频汇聚平…

【含开题报告+文档+PPT+源码】贫困儿童一对一扶贫帮扶系统设计与实现

开题报告 根据《中华人民共和国慈善法》第五十八条规定&#xff0c;慈善组织确定慈善受益人&#xff0c;应当坚持公开、公平、公正的原则&#xff0c;不得指定慈善组织管理人员的利害关系人作为受益人[2]。以上所列举的平台基本没有做到公开、公平、公正的原则&#xff0c;例如…

OpenAI Canvas用户反馈:并不如外界传言般“炸裂”,更不是“AGI的终极交互形态” | LeetTalk Daily...

“LeetTalk Daily”&#xff0c;每日科技前沿&#xff0c;由LeetTools AI精心筛选&#xff0c;为您带来最新鲜、最具洞察力的科技新闻。 Canvas作为一个独立的界面&#xff0c;通过与ChatGPT的结合来提升用户的协作能力和创作效率。尽管用户对其独立性与现有工具的整合存在不同…

大模型常见算子定义

本文将汇总大模型常用的算子定义&#xff0c;方便快速根据定义公式评估其计算量。 LayerNorm 这是在BERT、GPT等模型中广泛使用的LayerNorm&#xff1a; RMSNorm RMSNorm(root mean square)发现LayerNorm的中心偏移没什么用(减去均值等操作)。将其去掉之后&#xff0c;效果几乎…

如何将LiDAR坐标系下的3D点投影到相机2D图像上

将激光雷达点云投影到相机图像上做数据层的前融合&#xff0c;或者把激光雷达坐标系下标注的物体点云的3d bbox投影到相机图像上画出来&#xff0c;都需要做点云3D点坐标到图像像素坐标的转换计算&#xff0c;也就是LiDAR 3D坐标转像素坐标。 看了网上一些文章都存在有错误或者…