我们是否曾经在Java中使用volatile关键字?

时间:2020-03-06 14:28:23  来源:igfitidea点击:

今天的工作中,我遇到了Java中的volatile关键字。不太熟悉,我找到了以下解释:

Java theory and practice: Managing volatility

鉴于该文章详细解释了所讨论的关键字,我们是否曾经使用过它,或者是否曾见过可以正确使用该关键字的情况?

解决方案

volatile修饰符可确保任何读取字段的线程都将看到最新写入的值。乔什·布洛赫(Josh Bloch)
如果我们正在考虑使用" volatile",请阅读处理原子行为的包" java.util.concurrent"。
单例模式上的Wikipedia帖子显示使用情况不稳定。

绝对没错。 (不仅在Java中,而且在C#中也是如此。)有时,我们需要获取或者设置一个值,该值可以保证是给定平台上的原子操作,例如int或者boolean,但不需要线程锁定的开销。 volatile关键字使我们可以确保在读取值时获得的是当前值,而不是刚被另一个线程的写入废弃的缓存值。

volatile具有存储器可见性的语义。基本上,在所有读写器(特别是其他线程)上完成写操作之后," volatile"字段的值才变为可见。没有" volatile",读者可能会看到一些未更新的值。

回答问题:是的,我使用一个" volatile"变量来控制某些代码是否继续循环。循环测试" volatile"值,如果它是" true"则继续。可以通过调用"停止"方法将条件设置为"假"。在stop方法完成执行之后,循环将看到" false"并在测试该值时终止。

我强烈推荐的"实践中的Java并发性"一书很好地解释了" volatile"。这本书是由撰写该问题中引用的IBM文章的同一人撰写的(实际上,他在该书的底部引用了他的书)。我对volatile的使用是他的文章所说的"模式1状态标志"。

如果我们想了解有关volatile在幕后如何工作的更多信息,请阅读Java内存模型。如果我们想超越这一水平,请阅读Hennessy&Patterson这样的优秀计算机体系结构书籍,并了解有关缓存一致性和缓存一致性的信息。

使用volatile的一个常见示例是使用volatile布尔变量作为标志来终止线程。如果我们已经启动了一个线程,并且希望能够安全地从另一个线程中中断它,则可以让该线程定期检查一个标志。要停止它,请将标志设置为true。通过将标志设置为" volatile",可以确保正在检查它的线程在下次检查它时将看到它已被设置,而不必使用" synchronized"块。

是的,每当我们希望多线程访问一个可变变量时,都必须使用volatile。这不是很常见的用例,因为通常我们需要执行多个原子操作(例如,在修改变量之前检查变量状态),在这种情况下,我们将使用同步块。

如果要开发多线程应用程序,则需要使用" volatile"关键字或者" synchronized"关键字以及任何其他并发控制工具和技术。此类应用程序的示例是桌面应用程序。

如果我们正在开发将部署到应用程序服务器(Tomcat,JBoss AS,Glassfish等)的应用程序,则不必自己处理并发控制,因为应用程序服务器已经解决了并发控制问题。实际上,如果我没记错的话,Java EE标准禁止在servlet和EJB中进行任何并发控制,因为它是"基础结构"层的一部分,我们应该免于对其进行处理。如果要实现单例对象,则只能在此类应用程序中进行并发控制。如果我们使用像Spring这样的框架来编织组件,这甚至已经解决了。

因此,在大多数Java开发中,其中应用程序是Web应用程序,并使用IoC框架(例如Spring或者EJB),则不需要使用" volatile"。

是的,我经常使用它,它对于多线程代码非常有用。我们所指的文章是一篇不错的文章。尽管有两点要牢记:

  • 仅当我们完全了解volatile以及它与同步有何不同时,才应使用volatile。在许多情况下,表面上看起来易失性是同步的一种更简单,更高性能的替代方法,而通常人们对易失性的更好理解会清楚地表明,同步是唯一可行的选择。
  • volatile实际上在许多旧版JVM中均不起作用,尽管已同步。我记得看到过一个文档,其中引用了不同JVM中的各种支持级别,但不幸的是我现在找不到它。如果我们使用的是Java 1.5之前的版本,或者我们无法控制程序将在其上运行的JVM,那么一定要仔细研究一下。

volatile对于停止线程非常有用。

Java 1.6具有很多不错的线程池,而不是我们应该编写自己的线程。但是,如果确定需要一个线程,则需要知道如何停止它。

我用于线程的模式是:

public class Foo extends Thread {
  private volatile boolean close = false;
  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

注意如何不需要同步