【javaEE面试题(五)在JMM(Java Memory Model (Java 内存模型))下谈volatile的作用】

news2024/11/15 8:44:06

volatile的作用

        • JMM下volatile作用

在这里插入图片描述在这里插入图片描述

volatile 能保证内存可见性
volatile 修饰的变量, 能够保证 “内存可见性”.
在这里插入图片描述

代码在写入 volatile 修饰的变量的时候

  • 改变线程工作内存中volatile变量副本的值
  • 将改变后的副本的值从工作内存刷新到主内存

代码在读取 volatile 修饰的变量的时候

  • 从主内存中读取volatile变量的最新值到线程的工作内存中
  • 从工作内存中读取volatile变量的副本
    前面我们讨论内存可见性时说了, 直接访问工作内存(实际是 CPU 的寄存器或者 CPU 的缓存), 速度非常快, 但是可能出现数据不一致的情况.
    加上 volatile , 强制读写内存. 速度是慢了, 但是数据变的更准确了.

代码示例

在这个代码中

  • 创建两个线程 t1 和 t2
  • t1 中包含一个循环, 这个循环以 flag == 0 为循环条件.
  • t2 中从键盘读入一个整数, 并把这个整数赋值给 flag.
  • 预期当用户输入非 0 的值的时候, t1 线程结束.
import java.util.Scanner;

public class ThreadVolatile {
    static class Counter {
        public int flag = 0;
    }
        public static void main(String[] args) {
            Counter counter = new Counter();
            Thread t1 = new Thread(() -> {
                while (counter.flag == 0) {
                    // do nothing
                }
                System.out.println("循环结束!");
            });
            Thread t2 = new Thread(() -> {
                Scanner scanner = new Scanner(System.in);
                System.out.println("输入一个整数:");
                counter.flag = scanner.nextInt();
            });
            t1.start();
            t2.start();
        }
}

// 执行效果
// 当用户输入 非0值 时, t1 线程循环不会结束. (这显然是一个 bug)
  • t1 读的是自己工作内存中的内容.
  • 当 t2 对 flag 变量进行修改, 此时 t1 感知不到 flag 的变化

如果给 flag 加上 volatile

static class Counter {
    public volatile int flag = 0; 
}
// 执行效果
// 当用户输入非0值时, t1 线程循环能够立即结束.

volatile 不保证原子性

volatile 和 synchronized 有着本质的区别. synchronized 能够保证原子性, volatile 保证的是内存可见性.

代码示例
这个是最初的演示线程安全的代码

  • 给 increase 方法去掉 synchronized
  • 给 count 加上 volatile 关键字.
static class Counter {
    volatile public int count = 0;
    void increase() {
        count++;
   }
}
public static void main(String[] args) throws InterruptedException {
    final Counter counter = new Counter();
    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 50000; i++) {
            counter.increase();
       }
   });
    Thread t2 = new Thread(() -> {
        for (int i = 0; i < 50000; i++) {
            counter.increase();
       }
   });
    t1.start();
    t2.start();
    t1.join();
    t2.join();
    System.out.println(counter.count);
}

此时可以看到, 最终 count 的值仍然无法保证是 100000.

JMM下volatile作用

正常程序执行的过程中,会把主内存的数据,先加载到工作内存中,再进行计算处理.编译器优化可能会导致不是每次都真的读取主内存,而是直接取工作内存中的缓存数据.(就可能导致内存可见性问题)
volatile 起到的效果,就是保证每次读取内存都是真的从主内存重新读取

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

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

相关文章

B067-基础环境-抽取Basegit

目录 抽取base抽取domain和querymapper接口抽取service抽取 Git优点&#xff1a;Git安装及操作Git Bash命令行操作图形化客户端TortoiseGit操作Git集成Idea操作idea会把workspace作为本地仓库gitee操作idea解决代码冲突 抽取base 抽取domain和query domain&#xff1a;所有实体…

Nodejs 依赖包的存放路径设置(按其他博客修改路径后,安装路径仍在C盘的解决办法)

Nodejs 依赖包的存放路径设置 使用命令npm root -g 查看依赖包的安装位置 默认依赖包的安装位置是在C盘。为了防止C盘存太多东西&#xff0c;我这里已经将安装位置改到了D盘&#xff0c;下面就记录下修改的步骤。 1. 创建新的依赖包安装目录 在 nodejs 的安装目录下创建两个新…

8年资深测试总结,性能测试+性能优化(详细)进军高级测试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能优化常见概念…

LabVIEW FPGA利用响应式数字电子板快速开发空间应用程序

LabVIEW FPGA利用响应式数字电子板快速开发空间应用程序 与传统的基于文本的语言相比&#xff0c;LabVIEW的编程和设计已被证明可以缩短开发时间。各种研究表明&#xff0c;生产率的提高在3到10倍之间。LabVIEW通过图形语言、集成开发环境和多个编译器的组合来实现这一点。 图…

qt对话框

完善文本编辑器 #include "second.h" #include "ui_second.h"second::second(QWidget *parent) :QWidget(parent),ui(new Ui::second) {ui->setupUi(this);this->setWindowTitle("聊天室界面");//设置标题this->setWindowIcon(QIcon(&…

边缘检测

目录 1、边缘检测原理 2、Sobel算子边缘检测 3、Scharr算子边缘检测​编辑 4、算子生成函数 5、Scharr、Sobel的使用 6、Laplacian算子边缘检测 7、Canny算子边缘检测 8、Laplacian、Canny的使用 1、边缘检测原理 2、Sobel算子边缘检测 3、Scharr算子边缘检测 4、算子生成函…

MySQL数据库 - 表的操作

目录 一、创建表 二、创建表案例 1、显示当前使用的数据库名 2、创建表 2.1 MyISAM存储引擎表 2.2 InnoDB存储引擎表 三、查看表结构 四、修改表 1、新增列 2、修改列类型 3、修改列名 4、修改表名 5、删除列 五、删除表 表的操作至少会涉及如下两类SQL语句&…

adb日常使用命令

重启电脑adb服务 adb start-server和adb kill-server mac中uiautoviewer的位置 android-sdk→tools→bin→uiautomatorviewer.bat adb查看本机abi类型 adb shell getprop ro.product.cpu.abi github 比较好的adb教程&#xff1a; https://github.com/mzlogin/awesome-adb a…

[VUE学习]权限管理系统前端vue实现9-动态路由,动态标签页,动态面包屑

1.动态路由 1.因为我们左侧权限菜单是根据不同用户显示不一样的 所以我们需要使用动态路由 来动态生成右侧路由信息 在总体布局页面添加router <router-view> 是 Vue Router 提供的组件&#xff0c;用于动态展示匹配到的路由组件内容。通过在合适的位置放置 <router-v…

将word中超链接的字体颜色更换成白色

文章目录 1、问题描述2、解决方法&#xff08;两种&#xff09;2.1 临时修改2.2 永久修改 1、问题描述 超链接是蓝色&#xff0c;需要将其换成正常颜色的字体 2、解决方法&#xff08;两种&#xff09; 2.1 临时修改 直接选中该字体&#xff0c;从字体的颜色那里选主题颜色…

zabbix安装监控客户端应用

添加 zabbix 客户端主机 服务端和客户端都配置时间同步 服务端和客户端都设置 hosts 解析 设置 zabbix 的下载源&#xff0c;安装 zabbix-agent2 在服务端验证 zabbix-agent2 的连通性 ​编辑 在 Web 页面中添加 agent 主机 自定义监控内容 在客户端创建自定义 key 1.明确…

XSS学习

目录 什么是XSS 概念 理解 XSS分类 存储型XSS 反射型XSS 原理 攻击过程 DOM型 攻击过程 DOM行XSS与反射型XSS区别 存储型XSS与反射型XSS区别 DVWA实验 反射型XSS low等级 JavaScript弹窗函数 攻击思路 攻击者web设计 medium等级 high等级 impissible等级 …

【ES6】中构造函数的语法糖 —— Class(类)

在现代前端开发中&#xff0c;JavaScript的面向对象编程成为了主流。ES6引入了class关键字&#xff0c;使得开发者可以更方便地使用面向对象的方式编写代码&#xff0c;更接近传统语言的写法。ES6的class可以看作是一个语法糖&#xff0c;它的绝大部分功能ES5都可以做到&#x…

Java基础---动态代理

目录 典型回答 静态代理和动态代理的区别 动态代理的用途 Spring AOP的实现方式 JDK 动态代理的代码段 Cglib动态代理的代码段 典型回答 动态代理就是&#xff0c;在程序运行期&#xff0c;创建目标对象的代理对象&#xff0c;并对目标对象中的方法进行功能性增强的一种技…

electron+vue3全家桶+vite项目搭建【22】vite定义编译时全局变量,用于渲染进程判断当前是否为打包环境

引入 demo项目地址 我们在本地运行时往往显示的是一些方便调试的页面&#xff0c;如下所示: 通过页面路由选择&#xff0c;快速打开不同的窗口 而当我们打包运行时&#xff0c;往往希望直接进入软件的主页&#xff0c;而不显示这些调试页面&#xff0c;也许你会觉得&#xf…

设计模式之三:装饰者模式

装饰者模式可以在不修改任何底层代码的情况下&#xff0c;给对象赋予新的职责&#xff08;使用对象组合的方式&#xff0c;在运行时装饰类&#xff09;。 假定星巴兹咖啡需要更新订单系统&#xff0c;而他们原先类的设计如图&#xff1a; 现在他们考虑客户可以选择添加调料&am…

day62_ssm事务

今日内容 零、 复习昨日 零、 复习昨日 excel导入导出,cv配置和方法 aop: 面向切面编程 抽取与业务无关的代码,比如日志记录,事务控制,权限校验等,形成一个切面 利用动态代理的技术将切面中的增强方法,作用到目标方法上 aop日志 日志注解切面类 切入注解获得时间,ip,session中的…

跟我一起从零开始学python(四)数据库编程:MySQL数据库

前言 回顾之前讲了python语法编程 &#xff0c;必修入门基础和网络编程&#xff0c;多线程/多进程/协程等方面的内容&#xff0c;今天到了数据库编程篇&#xff0c;前面没看的也不用往前翻&#xff0c;系列文已经整理好了&#xff1a; 1.跟我一起从零开始学python&#xff08…

探索MySQL的秘密宝藏:寻找隐藏的金币数据!(面试)

目录 ✨前言 &#x1f6b6;‍♂️正片开始 一、常见MySQL面试题通关详解 二、SQL面试题实战 1. 某外卖公司的用户订单表面试题 2. 学生管理系统表面试题 &#x1f44b;尾记 前言 在一个神秘的岛屿上&#xff0c;有一个被称为"数据库之塔"的巨大建筑。据传说&a…

Kubernetes Pod卷 - Pod镜像的升级和回滚 - 探针

目录 扩展&#xff1a; Pod创建的拓扑图&#xff1a; 提出的问题&#xff1a; Pod 卷的使用&#xff1a;Pod的数据持久化问题 配置 Pod 以使用卷进行存储 参考文档&#xff1a;配置 Pod 以使用卷进行存储 | Kubernetes 有状态应用和无状态应用&#xff1a; Pod 配置卷 1…