假设我有一个课程如下:
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,所以需要做任何事情以确保这是线程安全的吗?
由于
答案 0 :(得分:3)
我有点困惑,因为我知道双打的读取不是原子的,但是因为这个类没有setter或getter,所以需要做任何事情来确保这是线程安全的吗?
是的,您需要确保x
和y
被标记为final
。这与double
无关。当构造final
(应该vector
btw)时,Vector
字段可以保证完全初始化。没有final
如果您在没有同步的情况下共享vector
的实例,编译器可以重新排序字段初始化过去构造函数完成时的点和x
和y
字段可能未初始化或部分未初始化。因此,另一个线程可能会将x
和y
视为0或仅更新其中一个字。有关详细信息,请参阅Constructor synchronization in Java
如果您正在使用可变字段(不能是final
),那么double
是否会完全更新取决于您运行的体系结构上。为了安全起见,您必须让他们volatile
确保在更改后对其进行全面更新和发布。
正如@Voo指出的那样,如果您要更新x
然后y
那么这是两个单独的操作,您的距离计算可能只会看到两个字段中的一个更新 - 即使它们是两个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;
}