【Java】volatile-内存可见性问题

1、什么是内存可见性问题?

(1)实例

要明白什么是内存可见性,我们首先来看一段代码

public class demo1 {
    public static int isQuit = 0;

    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            while (isQuit == 0){

            }
            System.out.println("t1线程结束");
        });
        thread1.start();

        Thread thread2 = new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            isQuit = scanner.nextInt();
            System.out.println("isQuit已被修改");
        });
        thread2.start();
    }
}

运行结果如下

打开jconsole,查看thread1状态,发现thread1还在运行状态,也就是说thread1中的while循环还一直在继续

为什么会这样呢?

(2)内存可见性问题 

在计算机中,CPU在读取寄存器时比读取内存时快很多,这时编译器会对代码进行自动优化

在上述代码中,由于while循环中没有代码,线程1不断地读取isQuit的值进行判断,操作过于频繁

因此,编译器在第一次读取isQuit的值后,便将其存放在寄存器中,后续不再读取

导致我们在线程2里对isQuit 的值进行了修改,线程1也不能察觉

由此便产生了内存可见性问题

2、volatile

要解决内存可见性问题,我们首先想到的是使用Java中的关键字volatile

在变量前加上关键字volatile修饰,变量便不会再被编译器优化,进而就不会产生内存可见性问题

public volatile static int isQuit = 0;

完整代码如下

import java.util.Scanner;

public class demo2 {
    public volatile static int isQuit = 0;

    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            while (isQuit == 0){

            }
            System.out.println("t1线程结束");
        });
        thread1.start();

        Thread thread2 = new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            isQuit = scanner.nextInt();
            System.out.println("isQuit已被修改");
        });
        thread2.start();
    }
}

最终运行结果

可见,内存可见性问题可用volatile关键字来解决

3、其他解决办法

 之所以产生内存可见性问题,是由于读取操作太过于频繁。只要我们降低读取的频率,同样也可以解决内存可见性问题

如在线程1中的while循环中加上sleep操作

import java.util.Scanner;

public class demo3 {
    public static int isQuit = 0;

    public static void main(String[] args) {
        Thread thread1 = new Thread(()->{
            while (isQuit == 0){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t1线程结束");
        });
        thread1.start();

        Thread thread2 = new Thread(()->{
            Scanner scanner = new Scanner(System.in);
            isQuit = scanner.nextInt();
            System.out.println("isQuit已被修改");
        });
        thread2.start();
    }
}

运行结果

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

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

相关文章

基于单片机K型热电偶温度采集报警系统

**单片机设计介绍, 基于单片机K型热电偶温度采集报警系统 文章目录 一 概要简介系统特点系统组成工作原理应用领域 二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 # 基于单片机K型热电偶温度采集报警系统介绍 简介 该系统是基于单片…

PDF控件Spire.PDF for .NET【转换】演示:自定义宽度、高度将 PDF 转 SVG

我们在上一篇文章中演示了如何将 PDF 页面转换为 SVG 文件格式。本指南向您展示如何使用最新版本的 Spire.PDF 以及 C# 和 VB.NET 指定输出文件的宽度和高度。 Spire.Doc 是一款专门对 Word 文档进行操作的 类库。在于帮助开发人员无需安装 Microsoft Word情况下,轻…

【2023云栖】陈守元:阿里云开源大数据产品年度发布

本文根据 2023 云栖大会演讲实录整理而成,演讲信息如下: 演讲人:陈守元 | 阿里云计算平台事业部开源大数据产品总监 演讲主题:阿里云开源大数据产品年度发布 随着云计算的不断发展,未来数据处理和应用的趋势将围绕C…

镭速,克服UDP传输缺点的百倍提速传输软件工具

在网络传输中,我们经常会面临这样的困难:文件太大,传输速度太慢,浪费时间和流量;文件太小,传输速度太快,容易出现丢包和乱序,损害数据的完整性和正确性。这些困难的根本在于传输层协…

mongoDB安装教程

安装及操作命令 cd /opt wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.4.0.tgz tar -zxvf mongodb-linux-x86_64-3.4.0.tgz#修改文件夹名字为mongodb-3.4.0 mv mongodb-linux-x86_64-3.4.0 mongodb-3.4.0# 在/opt/mongodb-3.4.0/conf目录下创建mongo.co…

服务器数据恢复—OCFS2下raid5磁盘损坏导致阵列崩溃的数据恢复案例

服务器数据恢复环境: IBM某型号存储,6块sas硬盘组建一组raid5,划分一个lun分配给Linux服务器并格式化为OCFS2文件系统,共享给虚拟化使用,存放的数据包括24台liunx和windows虚拟机、压缩包文件和配置文件。 服务器故障…

Ubuntu——卸载、安装CUDA

【注】WSL的Ubuntu是不用安装CUDA的,因为它使用的是Windows的显卡驱动,所以如果WSL的CUDA出了问题,重新安装WSL即可! 1、卸载 安装完CUDA后,会提示如果要卸载CUDA可以使用下列方法。 首先终端进入cuda-uninstaller所…

【亚马逊云科技产品测评】活动征文|aws云服务器 + 微服务Spring Cloud Nacos 实战

文章目录 前言一、拥有一台Aws Linux服务器1.1、选择Ubuntu版本Linux系统1.2、创建新密钥对1.3、网络设置1.4、配置成功,启动实例1.5、回到实例区域1.6、进入具体的实例1.7、设置安全组 二、在Mac上连接Aws云服务,并安装配置JDK112.1、解决离奇的错误2.2…

初识分布式键值对存储etcd

欢迎大家到我的博客浏览。胤凯 (oyto.github.io)大家好,今天我带大家来学习一下 etcd。 一、什么是 etcd etcd 是一个开源的分布式键值存储系统,主要用于构建分布式系统中那点服务发现、配置管理、分布式锁等场景。它采用 Raft 一致性算法来确保所有节…

【Redis】渐进式遍历数据库管理

文章目录 渐进式遍历scan 数据库管理切换数据库清除数据库 获取当前数据库key的个数 渐进式遍历 Redis使⽤scan命令进⾏渐进式遍历键,进⽽解决直接使⽤keys获取键时能出现的阻塞问题。每次scan命令的时间复杂度是O(1),但是要完整地完成所有键的遍历&…

Linux本地WBO创作白板部署与远程访问

文章目录 前言1. 部署WBO白板2. 本地访问WBO白板3. Linux 安装cpolar4. 配置WBO公网访问地址5. 公网远程访问WBO白板6. 固定WBO白板公网地址 前言 WBO在线协作白板是一个自由和开源的在线协作白板,允许多个用户同时在一个虚拟的大型白板上画图。该白板对所有线上用…

python的socket模块以及通信相关学习笔记

Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯(最初设计是为了是使同一台计算机中的不同进程进行信息传递通信),最后拓展到可以使网络上两台计…

redis-持久化

目录 一、RDB RDB触发保存的两种方式 优劣势总结 二、AOF AOF持久化流程: 1、开启AOP 2、异常恢复 3、AOF的同步频率设置 4、ReWrite压缩 5、优劣势总结 Redis 4.0 混合持久化 redis是内存数据库,所有的数据都会默认存在内存中,如…

python爬虫SHA案例:某直播大数据分析平台

声明: 该文章为学习使用,严禁用于商业用途和非法用途,违者后果自负,由此产生的一切后果均与作者无关 一、找出需要加密的参数 js运行 atob(‘aHR0cDovL3d3dy5oaDEwMjQuY29tLyMvc2VhcmNoL3NlYXJjaA’) 拿到网址,F12打…

原理Redis-ZipList

ZipList 1) ZipList的组成2) ZipList的连锁更新问题3) 总结 1) ZipList的组成 ZipList 是一种特殊的“双端链表” ,由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作, 并且该操作的时间复杂度为 O(1)。 ZipListEntry: ZipList 中的Entry并不像…

re 2019安洵杯复现

game 64位elf,ollvm混淆,直接用deflat就能去混淆 展示的是去除之后 arr[ 1,0,5,3,2,7,0,0,8,8,0,9,0,5,0,0,2,0,0,7,0,0,1,0,5,0,3,4,9,0,1,0,0,3,0,0,0,1,0,0,7,0,9,0,6,7,0,3,2,9,0,4,8,0,0,6,0,5,4,0,8,0,9,0,0,4,0,0,1,0,3,0,0,2,1,0,3,0,7,0,4] f…

【小呆的力学笔记】有限元专题之循环对称结构有限元原理

文章目录 1. 循环对称问题的提出2. 循环对称条件2.1 节点位移的循环对称关系2.2 节点内力的循环对称关系 3. 在平衡方程中引入循环对称条件 1. 循环对称问题的提出 许多工程结构都是其中某一扇面的n次周向重复,也就是是周期循环对称结构。如果弹性体的几何形状、约…

【zabbix监控四】zabbix之监控tomcat服务报警

一、监控tomcat服务是否正常运行 1、客户端部署 首先要在zabbix-agent客户端上安装tomcat服务,并能正常启动和关闭 1.1 客户端编写脚本 vim /opt/tomcat.sh#!/bin/bash anetstat -natp |grep 8080|awk {print $6}|grep LISTEN if [[ $a LISTEN ]];thenecho &qu…

redis非关系型数据库(缓存型数据库)——中间件

【重点】redis为什么这么快?(应届) ①redis是纯内存结构,避免磁盘I/O的耗时 ②redis核心模块是一个单进程,减少线程切换和回收线程资源时间 ③redis采用的是I/O的多路复用机制(每一个执行线路可以同时完…

原理Redis-Dict字典

Dict 1) Dict组成2) Dict的扩容3) Dict的收缩4) Dict的rehash5) 总结 1) Dict组成 Redis是一个键值型(Key-Value Pair)的数据库,可以根据键实现快速的增删改查。而键与值的映射关系正是通过Dict来实现的。 Dict由三部分组成,分别…