volatile关键字如何工作?

如何解决volatile关键字如何工作?

我正在阅读有关volatile关键字的信息。阅读完volatile关键字后,请通过下面的示例进行进一步的了解。

public class TaskRunner {
 
    private static int number;
    private static boolean ready;
 
    private static class Reader extends Thread {
 
        @Override
        public void run() {
            while (!ready) {
                Thread.yield();
            }
 
            System.out.println(number);
        }
    }
 
    public static void main(String[] args) {
        new Reader().start();
        number = 42;
        ready = true;
    }
}

据我了解,在Java应用程序中,多个线程可以在任何时间访问共享数据结构。有些是第一次写入,有些是更新,有些则读取,依此类推。

因此,在发生这些情况时,每个线程仅从主内存访问shared data structure's值。但是有时,shared data structure上线程的运算值会保留在其缓存中,直到操作系统不将其放入主内存中为止。因此,在此持续时间内,如果任何其他线程访问共享数据结构,将不会获得更新的值,该值由最后一个线程更新并仍在其缓存中。

使用

Volatile时,一旦更改了共享数据结构值,应先将其移至主内存,然后再由其他任何线程访问它。是正确的理解吗?

在什么情况下,即使使用volatile后,线程仍然无法获得更新的值?

解决方法

但是有时候,线程在共享数据结构上的操作值会保留在其缓存中,直到操作系统不将其放入主内存中为止。因此,在此持续时间内,如果任何其他线程访问共享数据结构,将不会获得更新值,该值由最后一个线程更新并仍在其缓存中。

它不是操作系统。 JVM使用一条CPU指令来重置CPU缓存。老实说,这种说法也是不正确的,因为Java内存模型对这种指令一无所知。这是实现y_core=K.sum(y_true_f[1:3],axis=1) 行为的方法之一。

does volatile keword in java really have to do with caches?

,

Java是相当高级的:作为一种语言,它并不是为任何特定的CPU设计而设计的。此外,java编译为字节码,这是一种中间产品:Java不提供,也不具有让您编写低级CPU架构特定操作的目标。

但是,缓存是低级CPU架构特定的概念。当然,每个现代CPU都有它们,但是谁知道20年后会发生什么?

因此,就其对CPU缓存的影响而言,将volatile忽略了一些步骤。

volatile对您的Java代码有影响。通过向CPU发送一些有关刷新缓存的指令,可以当前在大多数VM上实现这种效果。

最好在Java级别本身处理volatile,而不是在“大多数VM都以这种方式很好地实现”级别处理-毕竟,这可能会改变。

java的设置方法基本上如下:

如果在Java中任意两行代码之间没有建立先于关系,那么您应该假定Java就像schroedinger的猫:每个线程都具有和不具有局部整个VM中加载的每个对象上每个字段的缓存副本,无论何时写入或读取任何内容,Universe都会掷一枚硬币,使用该硬币来确定是否获得该副本,并始终将其翻转以至于惹上您。在您自己的机器上进行测试时,硬币会翻转以使测试通过。在周末紧要关头的生产过程中,当有数百万美元投入生产时,它会翻转以使代码失败。

唯一的出路是确保您的代码不依赖于硬币翻转。

方法是使用before-before规则,您可以在Java内存模型中查看这些规则。

volatile是添加它们的一种方法。

在上面的代码中,没有volatile,Reader线程可能始终使用其ready的本地副本,因此即使您的主要设置{{1}已经好几个小时了,也永远无法准备就绪。 }为真。实际上,这不太可能,但是JMM表示允许VM在这里进行硬币翻转:它可能会让您的Reader线程几乎立即继续运行,可能会持续一个小时,甚至可能永远持续。完全合法-该代码已损坏,其行为取决于硬币翻转,这很糟糕。

但是,一旦您引入了volatile,就可以建立先后关系,现在可以保证Reader继续。有效地,volatile既禁用了如此标记的变量的coinflips,也建立了在读/写问题之前的

IF 线程在易失性变量中观察到更新后的值, THEN 在任何更新线程代码之前运行的所有行,表明变量与所有行具有先行关系将在读取更新的线程中的代码之后运行。

因此,要明确一点:

此处没有任何易失性标记,VM允许Reader永久挂起是合法的。让VM继续读取器也是合法的(让它观察到ready现在为ready,而Reader STILL仍然看到true为0(而不是42),即使它通过了就绪检查!-但这不是必须的,还允许VM让读取器从不通过就绪检查,或者让它通过就绪检查并观察42。它想要的;对于CPU,架构和月球相位的这种特殊组合,现在看来最快的东西。

易变,读者最终将继续而不是稍后继续学习,一旦这样做,它肯定会遵守number。但是,如果您交换42ready = true;,则不再授予保证。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-