java 挥发注解_Java的挥发性修饰符

java 挥发注解

不久前,我写了一个Java servlet过滤器,该过滤器在其init函数中加载配置(基于web.xml的参数)。 筛选器的配置缓存在私有字段中。 我在字段上设置了volatile修饰符。

后来,当我检查Sonar公司以查看是否在代码中发现任何警告或问题时,得知使用volatile违反了规定,我感到有些惊讶。 解释为:




通常使用关键字“ volatile”来微调Java应用程序,因此需要Java内存模型的专业知识。 而且,它的作用范围还有些未知。 因此,volatile关键字不应用于维护目的和可移植性。

我同意volatile是许多Java程序员所不知道的。 对于一些甚至未知。 不仅因为它从一开始就没有使用太多,还因为它的定义自Java 1.5起就发生了变化。

让我稍微回顾一下Sonar的违规行为,并首先解释volatile在Java 1.5及更高版本中的含义(直到撰写本文时Java 1.8)。

什么是挥发物?

尽管volatile修饰符本身来自C,但在Java中它具有完全不同的含义。 这可能无助于加深对它的理解,使用谷歌搜索挥发物可能会导致不同的结果。 让我们快速迈出第一步,看看volatile在C语言中的含义。

在C语言中,编译器通常假定变量无法自行更改值。 尽管这是默认行为,但有时变量可能表示可以更改的位置(例如硬件寄存器)。 使用易失性变量指示编译器不要应用这些优化。

回到Java。 C中的volatile的含义在Java中将毫无用处。 JVM使用本机库与操作系统和硬件进行交互。 此外,将Java变量指向特定地址根本是不可能的,因此变量实际上不会自行更改值。

但是,JVM上变量的值可以由不同的线程更改。 默认情况下,编译器假定变量不会在其他线程中更改。 因此,它可以应用优化,例如对存储器操作重新排序以及将变量缓存在CPU寄存器中。 使用易失性变量指示编译器不要应用这些优化。 这样可以保证读取线程始终从内存(或共享缓存)中读取变量,而不从本地缓存中读取变量。

原子性

此外,关于32位JVM volatile的更多信息将写入到64位可变原子(如long s和double s)。 要写入变量,JVM会指示CPU将操作数写入内存中的某个位置。 使用32位指令集时,如果变量的大小为64位怎么办? 显然,该变量必须用两条指令(一次32位)写入。

在多线程方案中,另一个线程可能会在写入过程中读取变量。 此时,仅写入变量的前半部分。 这种争用条件可以通过可变的方式来防止,从而有效地使对32位体系结构的64位变量进行原子写操作。

请注意,上面我谈到的是而不是更新 。 使用volatile不会使更新原子化。 例如,当i易失时, ++i将从堆或L3缓存中读取i的值到本地寄存器inc中,然后将该寄存器写回到i的共享位置。 在读写之间, i可能会被另一个线程更改。 在读写指令周围加一个锁,使更新成为原子操作。 或更妙的是,使用concurrent.atomic包中原子变量类的非阻塞指令。

副作用

volatile变量在内存可见性方面也有副作用。 当线程读取volatile变量时,不仅对volatile变量的更改对其他线程可见,而且导致更改的代码的任何副作用也可见。 或更正式地说,易失性变量与该变量的后续读取之间建立事前关联。

即,从内存可见性的角度来看,有效地写入易失性变量就像退出同步块并读取易失性变量就像进入变量一样。

选择易失性

回到我使用volatile一次初始化配置并将其缓存在私有字段中的情况。
到目前为止,我相信确保此字段对所有线程可见的最佳方法是使用volatile。 我本来可以使用AtomicReference 。 由于该字段仅被写入一次(构造之后,因此不可能是最终的),因此原子变量传达了错误的意图。 我不想使更新原子化,我想使缓存对所有线程可见。 对于它的价值,原子类也使用volatile。

关于声纳法则的思考

既然我们已经了解了volatile在Java中的含义,那么让我们进一步讨论一下Sonar规则。

我认为该规则是Sonar之类的工具配置中的缺陷之一。 如果需要跨线程共享(可变)状态,那么使用volatile可能是一件非常好的事情。 当然,您必须将此保持在最低水平。 但是,此规则的结果是,不了解什么是挥发物的人会遵循建议不要使用挥发物。 如果他们有效地删除修饰符,则会引入竞争条件。

我确实认为使用未知或危险的语言功能时自动升起红色标记是个好主意。 但是,当有更好的替代方法来解决同一问题时,也许这只是一个好主意。 在这种情况下,volatile没有其他选择。

请注意,这绝不是对Sonar的指责。 但是我确实认为人们应该选择一套他们认为重要的规则来应用,而不是采用默认配置。 我发现使用默认情况下启用的规则的想法有点天真。 您的项目很有可能不是工具维护者在选择其标准配置时考虑的项目。

此外,我相信当您遇到不知道的语言功能时,您应该了解它。 当您了解它时,可以决定是否有更好的选择。

实践中的Java并发

关于JVM中并发的事实上的标准书是Brain Goetz编写的Java Concurrency in Practice 。 它在几个详细级别上解释了并发的各个方面。 如果您在Java(或不纯的Scala)中使用任何形式的并发,请确保您至少阅读了这本出色的书的前三章,以对问题有一个较高的了解。

翻译自: https://www.javacodegeeks.com/2014/07/javas-volatile-modifier.html

java 挥发注解

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

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

相关文章

python 线程锁_python多线程编程(3): 使用互斥锁同步线程

问题的提出 上一节的例子中,每个线程互相独立,相互之间没有任何关系。现在假设这样一个例子:有一个全局的计数num,每个线程获取这个全局的计数,根据num进行一些处理,然后将num加1。很容易写出这样的代码&am…

Comnnect oracle,RAC监听日志与CRS日志

RAC监听日志:tnsname.oraCRS日志:位置:Oracle集群涉及的日志主要位于“$ORA_CRS_HOME/log”和“$ORACLE_HOME/log”目录中目录结构:tree -d $ORA_CRS_HOME/logtree -d $ORACLE_HOME/log禁止Clusterware在系统重启后自动启动&#…

python全栈开发百度云_价值2400 2016年11月全栈开发Flask Python Web 网站编程

01-计算机基础常识.mp4 02-Python语言概览、安装与运行.mp4 03-Python 变量、数据类型及存储.mp4 04-Python 常用数据类型概览.mp4 05-数值与字符串.mp4 06-列表list.mp4 07-字典表dict 与元组 tuple.mp4 08-文件与类型汇总.mp4 09-语句、表达式与if分支.mp4 10-循环语句.mp4 1…

Java / Spring:如何快速生成整个数据库CRUD REST API

随着时间的流逝,Spring框架已成为Java中使用最广泛的Web开发框架之一,这一点已变得显而易见。 在接下来的十年之际,Spring最受欢迎的模块Spring Boot刚刚进行了重大更新。 新的Spring Boot版本“ 2.2.0”和年份“ 2020”几乎完美匹配。 因此…

如何在虚拟linux环境运行python_Conda(Python)虚拟环境不能从Windows移植到Linux

在我的Windows 10计算机上,我使用以下命令创建了一个虚拟环境:>conda env export > environment.yml 我尝试在Windows系统上使用yml文件重新创建虚拟环境,效果很好。然后我转学了环境.yml在我的Linux机器(Ubuntu16.04.1&…

oracle两个表合并 sql,如何创建从两个表(Oracle DBMS)生成“合并”数据集的Select SQL语句?...

我最后做了两个步骤:第一步填充事件表1中的数据,第二步合并目标(第一步中的数据集)和另一个源之间的数据。请原谅我,因为法律原因,我不得不混淆表名并省略下面代码中的一些列。下面是SQL:INSERT INTO EVENTS_TARGET (VEHICLE_ID,EVENT_TYPE_ID,CLIENT_ID,EVENT_DATE,CREATED_DA…

php毕业设计遇到的问题,常见问题_php毕业设计_php课程设计_php大作业_原创作品下载网...

一、我们怎么交易?答:本站采用在线支付的方式,每个产品页面都有一个付款按钮,亲在线付款后页面会显示一个“订单号”,根据这个订单号在本站的下载页面(见顶部菜单)下载相应程序,注意,亲要在30分…

git maven 发布_Maven Git发布

git maven 发布在开始这篇文章之前,我需要指出我在去年才开始认真地与Git合作 。 不幸的是,我从事的许多项目仍在使用SVN或CVS,但现在我终于开始使用Git了 。 在过去的几年中,我使用Maven Release Plugin完成了许多软件发行。 我…

python界面长什么样图片_python界面是什么样的

安装完Python,在命令行输入“python”之后,如果成功,会得到类似于下面的窗口:可以看到,结尾有3个>符号(>>>)。>>>被叫做Python命令提示符(prompt)&…

php static 访问,使用PHP访问Static方法的最佳方法

这是我的课堂财产private $my_paths array(imagemagick > E:\Server\_ImageOptimize\ImageMagick,pngcrush > E:\Server\_ImageOptimize\pngCrush\pngcrush.exe,jpegtran > E:\Server\_ImageOptimize\jpegtran\jpegtran.exe,gifsicle > E:\Server\_ImageOptimize\…

python表格控件_python GUI库图形界面开发之PyQt5表格控件QTableView详细使用方法与实例...

PyQt5表格控件QTableView简介 在通常情况下,一个应用需要和一批数据进行交互,然后以表格的形式输出这些信息,这时就需要用到QTableView类了,在QTableView中可以使用自定义的数据模型来显示内容,通过setModel来绑定数据…

Java:Speedment 3.2的发布–现在启用轻量级数据库微服务

几种传统的ORM不能完全遵循Java模块封装(JPMS)。 这通常意味着在部署微服务时会使用很多不必要的文件和类。 最新的主要版本3.2的开源 Speedance通过引入模块系统支持来解决此问题,该模块支持对云应用程序进行有效部署并提供更严格的API。 …

Linux文件系统为,浅析Linux文件系统

原标题:浅析Linux文件系统一、文件系统层次分析由上而下主要分为用户层、VFS层、文件系统层、缓存层、块设备层、磁盘驱动层、磁盘物理层用户层最上面用户层就是我们日常使用的各种程序,需要的接口主要是文件的创建、删除、打开、关闭、写、读等。VFS层我…

求解出n以内所有能被5整除的正整数的乘积_所有最常见最经典的算法题都在这里了...

1、一群猴子排成一圈,按1,2,…,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去…,如此不停的进行下去,直到…

怎样使set现程变得安全_使不安全变得更加安全

怎样使set现程变得安全总览 如果直接使用Unsafe,则可能会导致JVM崩溃。 当您访问尚未映射的内存页面并且在Unix上的结果是SIGSEG(如果访问页面0)或SIGBUS(如果您访问另一个未映射的页面)时,会发生这种情况。…

linux lvm 系统快照,系统运维|在 LVM中 录制逻辑卷快照并恢复(第三部分)

LVM快照是以空间换时间时间的方式制作的lvm卷副本。它只在lvm中工作,并只在源逻辑卷发生改变时占用快照卷的空间。如果源卷的变化达到1GB这么大,快照卷同样也会产生这样大的改变。因而,对于空间有效利用的最佳途径,就是总是进行小…

Spring Annotations我从没有机会使用第2部分:@ConfigurationProperties

几天前,我在检查其他内容时不小心偶然发现了Spring Boot项目中的Spring注释。 我们都知道如何将带有“ Value”的属性值绑定到类,并且我们都知道如果要绑定多个属性,这可能会很麻烦。 Spring Boot可以为您提供帮助。 您可以使用“ Configura…

python语言变量随时声明_2. Go语言五种变量创建的方法

对于只有 Python 语言经验的朋友,也许会不太理解声明这个词,在 Python 中直接拿来就用,也不用声明类型啥的。 Go 语言是静态类型语言,由于编译时,编译器会检查变量的类型,所以要求所有的变量都要有明确的类…

linux netty udp服务端,Netty实现UDP服务端

### 前言在之前的文章我已经讲过了利用Netty实现UDP客户端,大家有兴趣的话,可以参看下面文章:[Netty实现UDP客户端](https://www.jianshu.com/p/5dbc6b3c9d94)今天就让我们来学习下利用Netty实现UDP服务端吧,这里我经过整合封装&a…

会java需要多久能学会python_java好学吗?零基础学java要多久?

java好学吗?零基础学java要多久? 时间:2019-05-21 来源:华清远见 2019年3月,tiOBE 公布了编程语言排行榜,正如官方所说,本月的排名几乎没有任何有趣的变化,排名前十的依然是&…