在java中读取双打是否可以线程安全?

时间:2014-02-26 23:30:19

标签: java multithreading

假设我有一个课程如下:

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,所以需要做任何事情以确保这是线程安全的吗?

由于

1 个答案:

答案 0 :(得分:3)

  

我有点困惑,因为我知道双打的读取不是原子的,但是因为这个类没有setter或getter,所以需要做任何事情来确保这是线程安全的吗?

是的,您需要确保xy被标记为final。这与double无关。当构造final(应该vector btw)时,Vector字段可以保证完全初始化。没有final如果您在没有同步的情况下共享vector的实例,编译器可以重新排序字段初始化过去构造函数完成时的点和xy字段可能未初始化或部分未初始化。因此,另一个线程可能会将xy视为0或仅更新其中一个字。有关详细信息,请参阅Constructor synchronization in Java

如果您正在使用可变字段(不能是final),那么double是否会完全更新取决于您运行的体系结构上。为了安全起见,您必须让他们volatile确保在更改后对其进行全面更新和发布。

正如@Voo指出的那样,如果您要更新x然后y那么这是两个单独的操作,您的距离计算可能只会看到两个字段中的一个更新 - 即使它们是两个volatile。如果你需要它是原子的那么你应该使用AtomicReference并且有一个小容器类,它包含 xyAtomicReference包裹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;
 }