3

我已经阅读了很多关于同步和可变关键字/idms 的帖子,我认为我正确理解了它们的工作原理以及何时使用它们。但是,我仍然对我正在尝试做的事情有些怀疑。考虑以下:

public class X {
  private volatile int x;

  public X(int x) {
    this.x = x;
  }

  public void setX(int x) {
    this.x = x;
  }  

  public int getX() {
    return x;
  }
} 

上面的一个非常简单且线程安全。现在考虑具有以下更改的相同类 X:

public class X {
  private volatile int x;
  private volatile Y yObj;
  private volatile boolean active;

  public X(Y yObj) {
    this.yObj = yObj;
    active = false;
    x = yObj.getY();
  }

  public void setX(int x) {
    if (active) throw new IllegalStateException()
    if (!yObj.isValid(x)) throw new IllegalArgumentException();
    this.x = x;  
  }

  public void setY(Y yObj) {
    if (active) throw new IllegalStateException();
    this.yObj = yObj;
    x = yObj.getY();
  }

  public int getX() {
    return x;
  }

  public Y getY() {
    return yObj;
  } 

  public synchronized void start() {
     if (active) throw new IllegalStateException();
     /*
      * code that performs some initializations and condition checking runs here
      * does not depend on x and yObj
      * might throw an exception
      */
      active = true;
  }

  public synchronized void stop() {
      if (!active) throw new IllegalStateException();
      /* some code in the same conditions of the comments in the start()
       * method runs here
       */
      active = false;
  }

  public boolean isActive() {
    return active;
  }
} 

现在,我声明确保每个线程在通过调用方法更改时看到yObj相同的对象引用。类的想法是在调用对象的设置器时为类提供一组(在此示例中仅为一个)引用值。问题是:volatilesetY(Y)YXX

  1. 仍然可以x声明为volatile并确保所有线程的共同可见性或需要进一步同步?
  2. 这个想法是使类的所有对象Y不可变。因此,我假设它的所有字段也必须是不可变的。使Y用户可实现但同时又是线程安全的最佳方法是什么?一个实现线程安全机制然后可以扩展的抽象类?目前,Y是一个带有getter方法的接口,可以实现,当然不是线程安全的。
  3. 从并发访问的角度来看,启动/停止机制是否正确实现?
4

1 回答 1

1

你的问题的症结在于,private volatile Y yObj;只做yObj参考volatile,而不是它的内容。

当您稍后这样做时,x = yObj.getY();您可能会请求访问非易失性变量,因此理论上可能是线程不安全的。

使yObj不可变可能会有所帮助,但执行起来会很困难。

您的启动/停止机制看起来不错,但我会使用AtomicBoolean, 删除同步并使用if(active.compareAndSet(false, true) { ...或类似的。

于 2013-07-27T21:46:40.360 回答