[多线程]线程安全问题再讨论 - 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…

【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 方式进行实现。在文章开始的过程,会先大概讲讲笔者遇到的情况,因为封装方式需要根据实际…

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

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

[c]求逆序数

#include<stdio.h> int main() {int n,i,count;scanf("%d",&n);int arr[n];count0;for(i0;i<n-1;i){scanf("%d",&arr[i]);}for(int j0;j<n-2;j)//注意是小于等于n-2&#xff0c;因为倒数第一个元素后面没有数了&#xff0c;不需要比较…

CSC173 Boolean Logic and Boolean Circuits

We have provided code for a simple Boolean circuit simulator written i n C

韵达速递查询,韵达速递单号查询,对需要的单号进行备注

批量查询韵达速递单号的物流信息&#xff0c;对需要的单号进行备注。 所需工具&#xff1a; 一个【快递批量查询高手】软件 韵达速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主界面左上角的“…

基于SpringBoot + vue的在线视频教育平台

qq&#xff08;2829419543&#xff09;获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;springboot 前端&#xff1a;采用vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xf…

王炸cpu-龙芯3A6000

国产 CPU 性能媲美 Intel 酷睿这事儿&#xff0c;可能真的已经实现了。 没错&#xff0c;那颗有着多次爆料拉满大家期待值的龙芯 3A6000&#xff0c;终于正式发布。 就在今天上午&#xff0c;龙芯中科在 2023 年龙芯产品发布暨用户大会上正式带来了这颗 CPU。 整场发布会 PPT …