[java]线程安全问题

2023-11-19

线程安全问题产生有五个产生原因:

(1)线程的随机调度和抢占式执行,就是这个机制使得线程安全问题产生;

(2)代码结构,多个线程对同一个变量进行修改

(3)原子性,修改操作的是可拆分的,导致脏读问题

(4)内存可见性问题(一个线程读一个线程写)

(5)指令重排序

我们接下来针对每种线程安全的产生原因,做出对应的应对方案

一 、线程的随机调度和抢占式执行

这是线程的基本特性,也是线程安全出现的根本原因,在java代码的编写层面,我们对这个原因无能为力。

二、代码结构,多个线程对同一变量进行修改

对于这个原因,在某些情况下,我们可以通过调整代码的结构,先让两个线程修改不同变量,最后将对不同变量的修改汇总到一个变量,也能完成任务,但是这需要特定的代码需求,不是所有的代码都能通过修改代码结构来避免线程安全问题;

三、原子性,修改操作可以拆分

修改操作可以被拆分是如何导致线程安全问题的呢,以count++为例,一++被分为三个阶段,load,add,save,loda就是从内存中将这个数据取得,add就是对这个数据在cpu中进行修改,save就是将修改后的数据保存回内存中,当多个线程同时对count进行修改时,由于修改操作是可以拆分的,所以线程完全有可能在执行到load或者add之后,CPU就跑去执行其他线程了,其他线程此时也会修改count,他load到的count和已经停在load或add操作的线程是一样的,当两个线程执行完两次++后,count最后只自增了一次;

实际的情况往往比上述过程更加复杂,很有可能count已经被自增了几百次了,此时又执行到了子层几百次之前load到count的线程,count一下就变回了自增几百次之前的的数值

只要我们让修改方法具有原子性,不可以被拆分,也能避免线程安全问题,javaz中实现"原子性"的方法就是加锁(synchronized 修饰),这个方法虽然并没有让修改方法变得不可拆分(执行修改操作时,线程也能进行切换),但是他让修改方法在被一个线程使用的时候,不能被其他线程使用,达到了和原子性一样的效果(这里加锁并没有真正意义上实现原子性,但是达成的效果和原子性是一样的)

四、内存可见性问题

我们先好好解释什么是内存可见性问题:

java编译器在运行代码时有时会对代码的执行进行优化,比如一个大量的循环的读取同一个变量线程代码,正常情况下,每次读取都要在内存中去取得该变量的值,但是编译器在判断这个变量每次都只是被读取,并没有被修改后,它就做了一个大胆的决定但是java编译器优化后,它只有第一次读取去内存中读,第一次读取完之后,他将读取后的值存放在cpu内部,以后每次读取都从cpu内部读取,(因为从cpu读取比从内存读取的速度快得多,所以这提高了代码的运行效率)

在单线程的情况下,上面的优化确实是没问题的,但是在多线程情况下,这个代码就回产生内存可见性问题

考虑以下情况:一个线程循环读取某个数据,判断这个数据是否等于某个值,另一个线程会修改这个数据来控制第一个线程的运行,当另一线程修改这个数据后,第一个线程读取不到被修改后的值,因为编译器将他优化为只能读取cpu中的数据,第一个线程无法读取到内存中被修改后的数据,此时就产生了内存可见性的问题

解决办法:

让编译器知道,读取的这个数据是易变的,是不能被优化的,就在这个数据前面加上volatile关键字,这个关键字加上之后,编译器就不会再针对这个变量进行优化

五、指令重排序

指令重排序也和编译器的优化有关

在创建一个变量,new object()时,执行的指令有三步:

(1)申请一个空间

(2)向这个空间装入实例的数据

(3)将这个空间的地址赋值给引用

编译器优化后,将123的执行顺序,改成了132,在单线程的情况下,这个优化也是没毛病的,在多线程时,又会出现问题,如果实例化的时候,执行完13后,cpu突然跑掉了,此时引用已经有了实际的空间地址,如果其他线程使用这个对象,将会得到错误的结果,这就是指令重排序导致的线程安全问题(这个线程安全在单例模式的懒汉模式下有应用)

解决方法也很简单,也是加上volatile关键子修饰这个变量

我们可以总结出volatile的两条作用:

(1)保证内存可见性:让一个线程等读取到另一个线程对内存数据的修改

(2)保证有序性:禁止指令重排序

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[java]线程安全问题 的相关文章

  • 从 Android 函数更新 Textview

    有人可以告诉我如何从函数更新 Android Textview 控件吗 我在互联网上进行了深入搜索 看到很多人都问同样的问题 我测试了线程但无法工作 有人有一个简单的工作示例吗 例如 调用一个函数 在循环中运行多次 并且该函数在 TextV
  • ZeroDateTimeBehavior=convertToNull 在使用 hibernate 的 jdbc url 中不起作用

    通过 extern 属性文件 url 指定如下 jdbc mariadb xxxxx 3306 xxxxx zeroDateTimeBehavior convertToNull 连接工作正常并且能够查询数据库 通过休眠 我创建了一个映射到带
  • java中高效的输入流到字符串方法

    因此 我在 Java 中的 诚然非常简单 应用程序上运行探查器 令我惊讶的是 仅次于需要在时间上发出 HTTP 请求的方法的是我的方法 inputStreamToString方法 目前它的定义如下 public static String
  • Android Studio 与 Google Play 服务的编译问题

    我正在运行 Android Studio 0 8 4 并在 Android Studio 0 8 2 上尝试过此操作 我正在运行 Java JDK 1 8 0 11 并尝试使用 JDK 1 8 0 05 每当我尝试构建我的 android
  • 无法在 Intellij 中运行主类[重复]

    这个问题在这里已经有答案了 我有以下项目结构 ProjectRoot src Main examples libs My src文件夹被标记为sources在 Intellij 中 现在 当我想运行 Main 类时 出现以下错误 Excep
  • Android 信号 11 (SIGSEGV),代码 1 (SEGV_MAPERR) libwebviewchromium.so

    对于 android 4 4 我多次收到 Native crash at system lib libwebviewchromium so 错误 以下是设备包括 Xperia Z1 SO 01F 16 30 2 Galaxy Tab4 7
  • 清空变量不会使方法引用无效[重复]

    这个问题在这里已经有答案了 为什么代码不抛出NullPointerException当我使用与变量绑定的方法引用时dog我后来分配了null to 我正在使用 Java 8 import java util function Functio
  • 在 doxygen 中使用 @see 或 @link

    我之前用 Javadoc 记录并使用了标签 see link or see foo and link foo 在我的描述中链接到其他课程 现在我尝试了doxygen 似乎这些标签不兼容 如果我运行 doxygen 完整的标签将被简单地解释为
  • java彩色滚动条搜索结果

    我将如何在 Java 中自定义滚动条 以便我可以进行像 chrome 一样的搜索 也就是说在结果所在的位置放置彩色条纹 我不想要一个库 因为我更喜欢自己编写代码 另外 我不想失去我拥有的 L F 欢迎举例 实际上 它将查看一个大的文本文件或
  • java.exe 以非零退出值 1 结束

    只是为了开始 我并不是真正尝试从 Android 中的 xlsx 文件中读取单元格 我已经尝试了几乎所有我在 Google 上搜索到的内容 但是每次 在两台不同的 PC 上 都是 Java 1 7 0 79 当我尝试构建 运行 这个应用程序
  • BigDecimal汇总统计

    我有一个 BigDecimal 列表 List
  • 如何在 JmsMessagingTemplate.sendAndReceive 上设置等待超时

    我在 MVC 控制器中使用 JmsMessagingTemplate 的 sendAndReceive 但如果没有发送回复消息 它似乎会永远等待回复 该文档指出 返回 回复 如果无法接收消息 例如由于超时 则可能为 null 然而 我只是不
  • Spring Security 角色层次结构不适用于 Thymeleaf sec:authorize

    我正在使用 Spring Security 3 2 5 RELEASE 和 ThymeLeaf 2 1 4 RELEASE 我已经在安全上下文中定义了角色层次结构 在我的视图层中我正在使用sec authorize属性来定义菜单项 我希望看
  • 向Java类库添加函数

    我使用的 Java 类库在很多方面都不完整 有很多类我认为应该内置其他成员函数 但是 我不确定添加这些成员函数的最佳实践 让我们调用不足的基类A class A public A long arbitrary arguments publi
  • Kotlin 支持 Java 11 吗?

    我尝试使用 Kotlin V1 2 70 Gradle V4 10 1 和 Java 11 使用 gradle 编译项目时 出现错误 未知 JVM 目标版本 11 支持的版本 1 6 1 8 Kotlin 编译器是否支持 Java 11 生
  • 如何更改 JAX-WS Web 服务的地址位置

    我们目前已经公开了具有以下 URL 的 JAX RPC Web 服务 http xx xx xx xx myservice MYGatewaySoapHttpPort wsdl http xx xx xx xx myservice MYGa
  • Spring 如何在运行时获取有关“强类型集合”的泛型类型信息?

    我在 Spring 3 0 文档中阅读了以下内容 强类型集合 仅限 Java 5 在 Java 5 及更高版本中 您可以使用强类型集合 使用泛型类型 也就是说 可以声明一个 Collection 类型 使其只能包含 String 元素 例如
  • Spring MVC:通用 DAO 和服务类

    我正在 Spring MVC 中编写网页 我使用 Generic DAO 编写了所有 DAO 现在我想重写我的服务类 我该如何写 通用服务 我的 DAO 如下 DAO package net example com dao import j
  • 亚马逊 Linux - 安装 openjdk-debuginfo?

    我试图使用jstack在 ec2 实例上amazon linux 所以我安装了openjdk devel包裹 sudo yum install java 1 7 0 openjdk devel x86 64 但是 jstack 引发了异常j
  • Graphics2D setfont() 严重减慢了 java 应用程序的启动速度

    我正在用java制作一个游戏 它每秒刷新60次 每次执行循环时 我都会使用 g2d 来绘制图像和字符串 如果我这样做的话一切都会很好g2d setFont new Font Arial Font PLAIN 8 和抽绳 这将是正常的 但如果

随机推荐

  • wmic命令学习

    我目前知道wmic可以查询进程 还可以查询服务 查询进程使用wmic process 如果想知道进程的名字 进程号 执行文件路径可以通过get来获取 还可以根据where筛选进程进行查询 wmic process get name proc
  • 开心档-软件开发入门教程网之Bootstrap4 信息提示框

    Bootstrap4 信息提示框 Bootstrap 4 可以很容易实现信息提示框 提示框可以使用 alert 类 后面加上 alert success alert info alert warning alert danger alert
  • Struts2 校验(XML配置校验)

    参考文档 http struts apache org 2 0 9 docs ajax client side validation html http struts apache org 2 0 9 docs pure javascrip
  • 基础篇-常用对称、非对称、摘要加密算法介绍

    本文属于 OpenSSL加密算法库使用系列教程 之一 欢迎查看其它文章 也可以查看 GmSSL国密加密算法库使用系列教程 常见的加密算法可以分成三类 对称加密算法 非对称加密算法 Hash算法 一 对称加密算法 对称加密是使用同一个密钥对信
  • springMVC基于Session实现动态国际化

    1 在spring配置文件中配置资源文件properties的位置及公共名 下列配置指定的properties文件处于src目录下的resources文件夹中 名字为message info properties
  • Unity 反射绑定UI

    ui的名称和定义的字段名要保持一致 using System using System Collections using System Collections Generic using System Linq using System
  • 计算机f g 盘找不到了,电脑E/F盘符突然不见了怎么办

    随着分区工具的普及 越来越多的人起初自己对硬盘重新界定分区 由于目前这些分区软件和平台不兼容造成再次分区的之后 分区会重叠 这会导致以后使用电脑的之后 会时常丢失一个或几个分区 1 首先开启磁盘管理 打开的步骤 右击桌面的计算机界面 管理
  • Compiler- volatile关键字

    为了直观的感受编译器为程序所做的编译优化 我们通过以下的C 程序来进行演示 只能体现编译优化的一小部分hh 请大家预测一下下面代码的输出结果 include
  • didChangeDependencies什么时候被调用

    参考 我先上一个Demo 这个Demo也就是网上面传的比较广的 我们就以这个来举例子说明网上的结论 父级结构中的层级发生变化时didChangeDependencies被调用 这个结论为什么是不完整 import package flutt
  • (2022 COLING)Context-Tuning情景化提示

    论文题目 Title Context Tuning Learning Contextualized Prompts for Natural Language Generation 研究问题 Question 自然语言生成 生成长文本 研究动
  • 5G+边缘计算,对于VR移动电竞游戏来说意味着什么?

    这是一个5G 边缘计算意义的问题 其实对VR游戏 特别是电竞游戏 这类大流量 低延迟的应用服务来说 大多数人第一时间想到的优点会是高达1Gbps s的数据传输速度 虽然事实确实如此 但并不是全部 从技术上讲 无线传输性能的进步能给我们带来更
  • element 可移动dialog

    import Vue from vue v dialogDrag 弹窗拖拽属性 Vue directive dialogDrag bind el binding vnode oldVnode const dialogHeaderEl el
  • ES6数组方法总结

    1 forEach let array 1 2 3 4 array forEach item index array gt console log item forEach会遍历数组 没有返回值 不允许在循环体内写return 不会改变原来
  • 小程序自定义导航栏返回主页

    小程序自定义导航栏返回主页 效果图 在app js中获取状态栏的高度statusBarHeight 自定义组件navbar wxml 自定义组件navbar wxss 自定义组件navbar json 自定义组件navbar js 调用组件
  • 睿智的目标检测60——Tensorflow2 Focal loss详解与在YoloV4当中的实现

    睿智的目标检测60 Tensorflow2 Focal loss详解与在YoloV4当中的实现 学习前言 什么是Focal Loss 一 控制正负样本的权重 二 控制容易分类和难分类样本的权重 三 两种权重控制方法合并 实现方式 学习前言
  • 如何用Stata完成(shui)一篇经济学论文(九):画线性图

    目录 普通线性图 多图并列 一图多线 什么 为什么只讲线形图 因为我只用过线形图 言归正传 我的确只用过线形图 说了跟没说一样 Stata画图给我的感觉一直都是很复杂 很多命令 我觉得好像也没有很多的地方要画图 一般就画个线形图看看趋势 如
  • 2023年,想要年赚百万必懂的道理?

    1 一个人只有经历过风雨沧桑 才会明白一个道理 这个世界最大的监狱就是人的思维 而越狱最好的方式就是人的觉醒 2 人活明白了就会知道 不要拿自己去跟别人比较 后果不是忘记了自己 就是让自己失落 3 如果一个人不向内求 总是拿自己的一点优势去
  • 机器学习可解释性

    20210508 随笔 后续有时间在对概念有了深入理解之后再进行整理 0 引言 今天不想写论文 就想起了之前关注的一个内容 机器学习的可解释性 在之前的时候 或多或少了解这个东西 发现他更多的是从特征的角度来解释 这个特征怎么影响了模型 但
  • python实现货币转换

    实现美元与人民币的转换 2022 4 16 1美元 6 37人民币 moneyStr input 请输入带有标志 RMB rmb USD usd 的钱数 if moneyStr 3 in RMB rmb dollar eval moneyS
  • [java]线程安全问题

    线程安全问题产生有五个产生原因 1 线程的随机调度和抢占式执行 就是这个机制使得线程安全问题产生 2 代码结构 多个线程对同一个变量进行修改 3 原子性 修改操作的是可拆分的 导致脏读问题 4 内存可见性问题 一个线程读一个线程写 5 指令