[多线程]线程安全问题再讨论 - volatile

目录

1.引言

2.volatil关键字

2.1内存可见性

2.2指令重排序


1.引言

  大家好,我是老cu,今天我们来继续聊聊线程安全问题 线程安全是我们在编程开发中遇到的非常常见,棘手 的问题.同时也是多线程部分很复杂的问题.为了线程安全我们要做很多努力.也要对线程安全部分的代码进行慎重的写,本篇文章,我们将继续围绕线程安全问题来展开.

2.volatil关键字

2.1内存可见性

我们先看下面的代码:

import java.util.Scanner;public class Test {public static int a = 0;public static void main(String[] args) {Thread t1 = new Thread(()->{while (a==0){}});Thread t2 = new Thread(()->{Scanner scanner = new Scanner(System.in);int b = scanner.nextInt();a=b;});t1.start();t2.start();}
}

很明显,上述代码是定义了一个全局静态变量a,并初始化为0,在t1线程里,通过while循环,如果a==0,则一直循环下去,在t2线程里改变a的值,理论上来说,如果我们输入一个非0的数,循环会停止.但是实际情况呢?

在我们运行以后发现,即使我们输入了一个数字循环还是没有结束.这是为什么呢?

  原来这是因为编译器为了执行效率,会进行优化,它检测到这个数字一直没有变化.本来的while循环步骤应该是直接在内存中读取a的值,然后在判断是否进行打印.但是为了效率,它优化的时候,发现这个数字并没有什么变化.就省去了去内存中读取这个步骤.直接从寄存器(工作内存)中读取数值a,此时我们在内存中修改这个数字,自然就影响不了结果了.

那么我们应该怎么做,可以让编译器每次在读取的时候,从内存中读取,而不是优化到寄存器中呢?

很简单,在这个变量前加入volatile关键字即可.

可以看到,加了这个volatile关键字以后,程序就能正常读取我们写入的数值了.

这就是volatile关键字的其中一个作用:解决内存可见性问题.

2.2指令重排序

为了举这个例子,我们先介绍一种设计模式-单例模式中的懒汉模式.单例模式是一种设计模式,它通过技巧,让一个类只能有一个对象,如果在实例化这个类,企图创建一个新的的对象就会报错.

当线程执行到new SingletonLazy();的时候

一般来说.new一个实例分为以下三步:
1.申请一块内存

2.实例化对象

3.将内存引用赋值

但是编译器有时候会进行指令重排序,上述的过程可能会变成 1 3 2 

在一个线程的时候,不会有什么问题.但是如果是两个线程的话

就会出现上述 的问题,为了解决它.我们可以将这个引用加入volatile关键字来禁止指令重排序:

class SingletonLazy{// 这个引用指向唯一实例. 这个引用先初始化为 null, 而不是立即创建实例private volatile static SingletonLazy singletonLazy = null;private static Object object = new Object();public static SingletonLazy getSingletonLazy() {if(singletonLazy == null){synchronized (object){if(singletonLazy == null){singletonLazy = new SingletonLazy();}}}return singletonLazy;}private SingletonLazy(){}
}

这样就不会再出现问题了

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

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

相关文章

使用python streamlit库快速创建一个购物网站

streamlit Streamlit 是一个基于 Python 的 Web 应用程序框架,致力于以更高效、更灵活的方式可视化数据,并分析结果。 Streamlit是一个开源库,可以帮助数据科学家和学者在短时间内开发机器学习 (ML) 可视化仪表板。只需几行代码&#xff0c…

[GPT-1]论文实现:Improving Language Understanding by Generative Pre-Training

Efficient Graph-Based Image Segmentation 一、完整代码二、论文解读2.1 GPT架构2.2 GPT的训练方式Unsupervised pre_trainingSupervised fine_training 三、过程实现3.1 导包3.2 数据处理3.3 模型构建3.4 模型配置 四、整体总结 论文:Improving Language Understa…

Gossip 协议

Gossip 协议 背景 在分布式系统中,不同的节点进行数据/信息共享是一个基本的需求。 一种比较简单粗暴的方法就是 集中式发散消息,简单来说就是一个主节点同时共享最新信息给其他所有节点,比较适合中心化系统。这种方法的缺陷也很明显&…

Hdoop学习笔记(HDP)-Part.20 安装Flume

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

ubuntu下快速搭建docker环境训练yolov5数据集

参考文档 yolov5-github yolov5-github-训练文档 csdn训练博客 一、配置环境 1.1 安装依赖包 前往清华源官方地址 选择适合自己的版本替换自己的源 # 备份源文件 sudo cp /etc/apt/sources.list /etc/apt/sources.list_bak # 修改源文件 # 更新 sudo apt update &&a…

LinuxBasicsForHackers笔记 --常用Linux命令

在终端中修改用户密码命令:passwd Linux的文件系统是逻辑文件系统。 Linux基本命令 pwd – print working directory. 返回你当前所在目录结构中的位置。 whoami – 查看您当前登录的用户身份。 cd – change directory. 从终端更改目录。 cd / – 移动到根目录…

数据结构与算法(Java) -单调队列单调栈题单

单调队列(灵神笔记) 239 滑动窗口最大值 239. 滑动窗口最大值 - 力扣(LeetCode) 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗…

Skywalking接入实际应用做日志跟踪

Skywalking客户端挂载 从官网下载skywalking-agent客户端,并挂在到应用服务器指定目录 挂载到应用主机中,好处是解决打包应用镜像的时候,镜像过大,部署成本过高。 docker-compose部署应用,并接入skywalking服务,这里以gateway为例 versio…

Webgis学习总结

前言: 作者跟随视频学习了webgis内容进行如下学习复习总结 参考:新中地学习笔记 WebGIS第一课:测试高德API并通过: 注册申请高德API成为开发者,创建自己的项目和key进行项目初始化,可以使用JS API官方文…

26. 深度学习进阶 - 深度学习的优化方法

Hi, 你好。我是茶桁。 上一节课中我们预告了,本节课是一个难点,同时也是一个重点,大家要理解清楚。 我们在做机器学习的时候,会用不同的优化方法。 SGD 上图中左边就是Batch Gradient Descent,中间是Mini-Batch Gra…

【Java】Java性能优化细节及使用场景

Java性能优化的细节非常多,涉及编码习惯、设计模式、JVM调优、算法优化等多个方面。以下是一些常见的优化细节及使用场景: 1. **使用单例模式适当地管理资源**:单例模式可以减少对象的创建和销毁开销,特别是在线程安全的情况下&am…

【Linux】第二十五站:深入理解文件系统

文章目录 一、前言二、认识硬件----磁盘1.基本介绍2.磁盘的存储构成3.磁盘的逻辑结构4.回归到硬件 三、文件系统1.划分2.Block group(1)Data blocks(2)inode Table(3)Block Bitmap(4)inode Bitmap(5)Group Descriptor Table(GDT)(6)Super Block 3.总结4.一些其他问题5.如何理解…

untiy webgl常见问题与操作

文章目录 1 untiy和网页相互通信2 打开新页面(同标签页和新标签页)3 获取网页的URL4 解析Url内的参数5 后处理与色彩空间问题 1 untiy和网页相互通信 看这个文章 2 打开新页面(同标签页和新标签页) 先看本文untiy和网页相互通信…

翻译: GPT4等大型语言模型的原理解析和未来预测慢思考和模型自我迭代和LLM安全

YouTube: Intro to Large Language Models - YouTube 1. Large Language Model LLM 大家好,最近我做了一个关于大型语言模型的 30 分钟演讲,有点像介绍性演讲,不幸的是,那个演讲没有被录制下来,但很多人在演讲结束后…

基于JNI实现调用C++ SDK

基于JNI实现调用C SDK 背景分析解决实践 背景 上篇文章总结了几种Java项目调用C/C SDK项目方法,在逐一实践、踩坑后,最终还是敲定采用 JNI 方式进行实现。在文章开始的过程,会先大概讲讲笔者遇到的情况,因为封装方式需要根据实际…

python部分题型

1 用过Python什么框架 1. **Django:** 用于构建Web应用程序的高级框架,提供了包括ORM(对象关系映射)、表单处理、模板引擎等在内的许多功能。2. **Flask:** 轻量级的Web框架,它提供了足够的灵活性&#xf…

MQTT客户端、代理(broker)和连接建立

在前篇文章(http://t.csdnimg.cn/IamPz)中,介绍了发布/订阅架构和MQTT如何据此交换信息,其中的关键概念是: 发布/订阅架构触耦了负责发布信息的客户端(发布者)和负责接收信息的客户端&#xff…

python basic3-zstarling

zstarling 1. map 函数匹配。成字典。2. 分组模糊匹配。3. 折线图的数据标签显示4. set_xticks() 无法识别列表5. set_xticklabels()会缺少一个值6. dtype()查看数据类型 ,astype()修改数据类型。7. object是指数值里有一个值是字符串类型,整体可以指字符串类型。8.…

每日一题(LeetCode)----哈希表--四数之和

每日一题(LeetCode)----哈希表–四数之和 1.题目(18. 四数之和) 给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四…

python——多线程的相关知识点总结

​​​​ 1.进程和线程的区别? 进程是操作系统分配资源的最小单位,每个进程都有自己独立的内存空间和系统资源。线程是操作系统能够进行运算调度的最小单位,它是进程内的基本单位,一个进程可以包含多个线程,这…