面试题:volatile

news/2024/11/17 1:53:13/

一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

1. 保证线程间的可见性

保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的,volatile关键字会强制将修改的值立即写入主存。

一个典型的例子:永不停止的循环

package com.itheima.basic;// 可见性例子
// -Xint
public class ForeverLoop {static boolean stop = false;public static void main(String[] args) {new Thread(() -> {try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}stop = true;System.out.println("modify stop to true...");}).start();foo();}static void foo() {int i = 0;while (!stop) {i++;}System.out.println("stopped... c:"+ i);}
}

当执行上述代码的时候,发现 foo() 方法中的循环是结束不了的,也就说读取不到共享变量的值结束循环。

主要是因为在JVM 虚拟机中有一个JIT(即时编辑器)给代码做了优化

上述代码

while (!stop) {
i++;
}

在很短的时间内,这个代码执行的次数太多了,当达到了一个阈值,JIT就会优化此代码,如下:

while (true) {
i++;
}

当把代码优化成这样子以后,及时stop变量改变为了false也依然停止不了循环

解决方案:

第一:

在程序运行的时候加入vm参数-Xint表示禁用即时编辑器,不推荐,得不偿失(其他程序还要使用)

第二:

在修饰stop变量的时候加上volatile,表示当前代码禁用了即时编辑器,问题就可以解决,代码如下:

static volatile boolean stop = false;

2. 禁止进行指令重排序

用 volatile 修饰共享变量会在读、写共享变量时加入不同的屏障,阻止其他读写操作越过屏障,从而达到阻止重排序的效果

在这里插入图片描述

在去获取上面的结果的时候,有可能会出现4种情况

情况一:先执行actor2获取结果 —> 0,0(正常)

情况二:先执行actor1中的第一行代码,然后执行actor2获取结果—>0,1(正常)

情况三:先执行actor1中所有代码,然后执行actor2获取结果—>1,1(正常)

情况四:先执行actor1中第二行代码,然后执行actor2获取结果—>1,0 (发生了指令重排序,影响结果)

解决方案

在变量上添加volatile,禁止指令重排序,则可以解决问题

在这里插入图片描述

屏障添加的示意图

在这里插入图片描述

  • 写操作 加的屏障是阻止上方其它写操作越过屏障排到volatile变量写之下
  • 读操作 加的屏障是阻止下方其它读操作越过屏障排到volatile变量读之上

其他补充

我们上面的解决方案是把volatile加在了int y这个变量上,我们能不能把它加在int x这个变量上呢?

下面代码使用volatile修饰了x变量

在这里插入图片描述

屏障添加的示意图

在这里插入图片描述

这样显然是不行的,主要是因为下面两个原则:

  • 写操作加的屏障是阻止上方其它写操作越过屏障排到volatile变量写之下
  • 读操作加的屏障是阻止下方其它读操作越过屏障排到volatile变量读之上

所以,现在我们就可以总结一个volatile使用的小妙招:

  • 写变量让volatile修饰的变量的在代码最后位置
  • 读变量让volatile修饰的变量的在代码最开始位置

http://www.ppmy.cn/news/1412384.html

相关文章

【C++】优先级队列(priority_queue)的用法与实现

目录 一、概念: 二、仿函数(Functor): 概念: 应用: 三、底层实现: 基本操作: 完整代码: 测试示例: 一、概念: 优先级队列(pri…

vue2 el-checkbox-group 复选框无法选中

vue2 el-checkbox-group 复选框无法选中 原代码&#xff1a; <template slot-scope"scope"><el-checkbox v-model"scope.row.bitian">必填</el-checkbox> </template>if (this.allTemplateList && this.allTemplateList…

OpenHarmony开发-连接开发板调试应用

在 OpenHarmony 开发过程中&#xff0c;连接开发板进行应用调试是一个关键步骤&#xff0c;只有在真实的硬件环境下&#xff0c;我们才能测试出应用更多的潜在问题&#xff0c;以便后续我们进行优化。本文详细介绍了连接开发板调试 OpenHarmony 应用的操作步骤。 首先&#xf…

lora微调过程

import os import pickle from transformers import AutoModelForCausalLM from peft import get_peft_config, get_peft_model, get_peft_model_state_dict, LoraConfig, TaskTypedevice "cuda:0"#1.创建lora微调基本的配置 peft_config LoraConfig(task_typeTask…

python 会员管理系统

问题介绍 综合案例&#xff1a;会员管理系统实现-V2版&#xff08;不可超前使用面向对象&#xff09; 利用函数&#xff0c;编写会员管理系统&#xff0c;实现进入系统显示系统功能界面&#xff0c;选择添加、删除、修改&#xff0c;查询、显示所有会员信息以及退出系统等响应…

【13137】第一章 质量与质量管理导论

目录 1.单选题 2.多选题 3.简答题 【13137】质量管理-考试分析: 1.单选题

基于SpringBoot注入Bean形式的监听(端口)

起一个线程、监听对应的端口,注入到容器 package com.port.component;import com.port.service.PortListenerService; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.CommandLineRunner; import org.springframework.stereoty…

线性变换在人工智能领域的深度实践与应用探索

线性变换&#xff0c;作为数学中的一种基本工具&#xff0c;在人工智能领域中发挥着举足轻重的作用。其强大的表示能力和灵活的运算特性使得线性变换成为机器学习、深度学习等多个子领域的核心组成部分。本文将详细探讨线性变换在人工智能领域中的实践应用&#xff0c;旨在揭示…