免费做金融网站,网站左侧漂浮导航,网站建站平台公司,网站建设运营案例java 挥发注解不久前#xff0c;我写了一个Java servlet过滤器#xff0c;该过滤器在其init函数中加载配置#xff08;基于web.xml的参数#xff09;。 筛选器的配置缓存在私有字段中。 我在字段上设置了volatile修饰符。 后来#xff0c;当我检查Sonar公司以查看是否在代… 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.htmljava 挥发注解