此类扩展Thread
,一旦创建,就会启动该线程。这是代码:
class Controller extends Thread implements ConfigurationObserver{
private int refreshMS;
//...
@Override
public void notifyConfiguration(ConfigurationModel config) {
refreshMS = config.getRefreshMs();
}
@Override
public void run() {
//...
while (true) {
try {
Thread.sleep(refreshMS);
} catch (InterruptedException ex) {
//...
}
}
}
}
它遵循Observer Pattern。该类将订阅ConfigurationController
,它将通过notifyConfiguration(...)
方法在每次配置参数发生更改时通知他。
让我对此有点不安全的是属性refresMS
。通过GUI(线程#1)更改配置,并影响从该类的运行线程(线程#3)读取的Controller
类(线程#2)的属性。
Q1:这会成为竞争条件吗? Q2:如果是,那么解决此问题的最佳方法是什么?
答案 0 :(得分:3)
第一季:这会成为竞争条件吗?
是。有点。 run()
方法最终可能会使用陈旧的refreshMS
值。
Q2:如果是这样,解决这个问题的最佳方法是什么?
这可以最大限度地减少竞争条件:
class Controller extends Thread implements ConfigurationObserver{
private int refreshMS;
public synchronized void notifyConfiguration(ConfigurationModel config) {
refreshMS = config.getRefreshMs();
}
public void run() {
while (true) {
...
synchronized (this) {
rms = refreshMS;
}
Thread.sleep(rms);
....
}
}
}
如果不在{/ 1}} 调用同步块中,则无法完全消除竞争条件。 (这会导致调用sleep
的线程阻塞可能无限长的时间。不好的主意。)
现在,这一切都很好,但你也应该问自己竞争条件是否可能对应用程序的执行产生有害影响。
答案 1 :(得分:2)
我所做的解决方案是建议的一个pingw33n。使用关键字volatile
。
class Controller extends Thread implements ConfigurationObserver{
private volatile int refreshMS;
//...
}
来自Brian Goetz's Managing Volatility
易失性变量共享同步的可见性功能,但是 没有原子性特征。这意味着线程会 自动查看volatile变量的最新值。
这意味着在极少数情况下可以使用volatile
代替synchronized
。但幸运的是,这是其中之一,因为int
是在原子上写的(没有线程可以读取其值,而其他人正在修改它)。
因此,正如斯蒂芬C所说,这并没有消除竞争条件,只会让它真的很少发生。在我的情况下,如果refresMS
被正在运行的线程用旧值重写(如果它几乎不发生的话)。