我一直在阅读很多关于同步和易变的关键字/ idoms的帖子,我想我已经正确理解它们是如何工作的以及何时应该使用它们。但是,我仍然对我正在尝试做的事情有些怀疑。请考虑以下事项:
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
声明为volatile
,以确保每个线程在通过调用setY(Y)
方法进行更改时看到相同的对象引用。 Y
类的想法是在调用X
对象的setter时为X
类提供一组参数值(在此示例中只是一个)。问题是:
x
仍然可以声明为volatile
,并确保所有线程的公共可见性或需要进一步同步吗?Y
的所有对象都是不可变的。所以,我假设它的所有字段也必须是不可变的。什么是使Y
用户可实现的最佳方法,但同时又是线程安全的?一个实现线程安全机制的抽象类,然后它可以扩展吗?目前,Y
是一个可以实现的getter方法的接口,当然,这不是线程安全的。答案 0 :(得分:1)
问题的关键在于private volatile Y yObj;
仅生成yObj
引用volatile
,而不是其内容。
当您稍后执行x = yObj.getY();
时,您可能正在请求访问非易失性变量,理论上该变量可能导致线程不安全。
使yObj
永久不变可能会有所帮助,但执行这将很困难。
您的启动/停止机制看起来不错,但我会使用AtomicBoolean
,删除同步并使用if(active.compareAndSet(false, true) { ...
或类似内容。