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;
}
}
Run Code Online (Sandbox Code Playgroud)
除了可以从另一个类更改的超时变量外,只从1个线程访问此类的实例.在我的例子中是一个JMX bean,这意味着可以在运行时从管理界面改变超时.
doStuff()可以运行100次/秒,而setTimeout()可以每周运行一次 - 因此执行setTimeout()的人和执行doWork()的人之间的顺序并不重要.
timeout在这种情况下是否足够挥发?内存模型是否可以保证从一个线程设置此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;
}
}
Run Code Online (Sandbox Code Playgroud)
哪两种方法更受青睐?
从可见性的角度来看,两种方法都是等价的.在对同一个volatile变量进行写操作之后发生的对volatile的任何读取都可以保证看到写入.
因此,如果一个线程写入timeout = newValue;,timer.schedule(timeout)则保证随后调用的任何其他线程都会看到newValue.
此保证在JLS 17.4.5中指定:
写入易失性字段(第8.3.1.4节) - 在每次后续读取该字段之前发生.
我会简单地使用volatile作为它提供的保证就足够了,它清楚地显示了你的意图.
| 归档时间: |
|
| 查看次数: |
909 次 |
| 最近记录: |