Java,volatile也会保证可见性吗?

标签 java concurrency

public class Stuff {
  private final Timer timer = new Timer(true);
  public static final int DEFAULT_TIMEOUT = 1500;
  private volatile int timeout = DEFAULT_TIMEOUT;


  public void doStuff(OtherStuff) {
     ...
     timer.schedule(timeout, ...);
  }

  public void setTimeout(int timeout) {
     this.timeout = timeout;
  }

  public int getTimeout() {
    return timeout;
  }

}

这个类的实例只能从一个线程访问,除了可以从另一个类更改的超时变量。在我的例子中是一个 JMX bean,这意味着可以在运行时从管理界面更改超时。

doStuff() 可以每秒运行 100 次,而 setTimeout() 可以每周运行一次 - 因此执行 setTimeout() 的人和执行 doWork() 的人之间的顺序并不重要。

timeout volatile 是否足以应对这种情况?内存模型是否保证从一个线程将其设置为对 doStuff() 方法可见?

另一种看似安全的替代方法就是:

public class Stuff {
  private final Timer timer = new Timer(true);
  public static final int DEFAULT_TIMEOUT = 1500;
  private int timeout = DEFAULT_TIMEOUT;
  public void doStuff(OtherStuff) {
     ...
     timer.schedule(getTimeout(), ...);
  }

  public void synchronized setTimeout(int timeout) {
     this.timeout = timeout;
  }
   public int synchronized getTimeout() {
    return timeout;
  }
}

这两种方法中哪一种是首选?

最佳答案

从可见性的角度来看,这两种方法是等效的。对同一个 volatile 变量的写入之后发生的对 volatile 的任何读取都保证可以看到写入。

因此,如果一个线程写入 timeout = newValue;,任何其他随后调用 timer.schedule(timeout) 的线程都保证看到 newValue .

此保证在 JLS 17.4.5 中指定:

A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field.

我会简单地使用 volatile,因为它提供的保证已经足够并且清楚地表明了您的意图。

关于Java,volatile也会保证可见性吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13592253/

相关文章:

java - 在 Java 的构造函数中使用 super() 有什么问题吗?

java - 将 AngularJs 对象映射/导航到 Hibernate 实体

java - OSGi 捆绑跟踪器 : order of tracked bundles

c# - Monitor.Pulse 和 Monitor.Wait 有什么优势?

java - Java代码中的Activiti工作流调用

java - 在 BoxLayout 中居中 JButton,JTextField 填充

java - Android (Java) 和 .NET DateTime 之间的高精度时间同步?

concurrency - MVCC & B-Tree & 并发

java - 字段读取同步和volatile的区别

http - 这个 goroutine 是如何失败的?