并发竞争条件?

时间:2012-06-12 11:08:32

标签: java concurrency

此类扩展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:如果是,那么解决此问题的最佳方法是什么?

2 个答案:

答案 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被正在运行的线程用旧值重写(如果它几乎不发生的话)。