假设我有一个类,如下所示:
public class vector{
public vector(double x, double y){
this.x = x;
this.y = y;
}
public double getDist() {
return Math.sqrt(x*x + y*y);
}
}
此代码是否与线程一起安全运行? 我有点困惑,因为我知道双打的阅读 不是原子的,但是因为这个类没有 setter 或 getter,所以需要做任何事情来确保它是线程安全的?
谢谢
我有点困惑,因为我知道双打的读取不是原子的,但是因为这个类没有二传手或getters,所以需要做些什么来确保这是线程安全的?
是的,您需要确保x
和y
标记为final
. 然而,这与它double
无关。final
字段保证在构造vector
(应该Vector
顺便说一句)时完全初始化。 如果没有final
,如果您共享了未同步的vector
实例,编译器可以在构造函数完成时对字段初始化重新排序,并且x
和y
字段可能未初始化或部分初始化。 因此,另一个线程可能会看到x
和y
为 0 或仅更新其中一个单词。 有关更多信息,请参阅 Java 中的构造函数同步
如果您正在处理可变字段(无法final
),那么double
是否会完全更新取决于您正在运行的体系结构。 为了安全起见,您必须将它们volatile
,以确保它们在更改时已完全更新和发布。
正如@Voo指出的那样,如果您正在更新x
然后y
那么这是 2 个单独的操作,您的距离计算可能只看到两个字段中的一个更新 - 即使它们都是volatile
。 如果你需要它是原子的,那么你应该使用一个AtomicReference
,并有一个保存x
和y
的小容器类。AtomicReference
包裹着volatile Object
.
像这样:
private final AtomicReference<XAndY> xyRef = new AtomicReference<XAndY>();
...
public void setXAndY(double x, double y) {
xyRef.set(new XAndY(x, y));
}
...
public double getDist() {
// get a local instance of our object which is atomic
XAndY xAndY = xyRef.get();
return Math.sqrt(xAndY.x * xAndY.x + xAndY.y * xAndY.y);
}
...
private static class XAndY {
double x;
double y;
}