繁体   English   中英

具有非final字段的不可变对象如何是线程不安全的?

[英]How can an immutable object, with non-final fields, be thread unsafe?

说我们有这个

// This is trivially immutable.
public class Foo {
    private String bar;
    public Foo(String bar) {
        this.bar = bar;
    }
    public String getBar() {
        return bar;
    }
}

是什么让这个线程不安全? 继这个问题之后

一旦安全发布, Foo就是线程安全的。 例如,这个程序可以打印“不安全”(它可能不会使用hotspot / x86的组合) - 如果你使bar最终它不会发生:

public class UnsafePublication {

    static Foo foo;

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (foo == null) {}
                if (!"abc".equals(foo.getBar())) System.out.println("unsafe");
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                foo = new Foo("abc");
            }
        }).start();
    }
}

由于JVM优化,您永远不能假设操作按照它们的编写顺序执行,除非它对同一个线程很重要。 因此,当您调用构造函数然后将对结果对象的引用传递给另一个线程时,JVM可能实际上不会在同一个线程中需要之前写入foo.bar的值。

这意味着在多线程环境中,可以在构造函数中的值写入之前调用getBar方法。

很可能你现在已经得到了答案,但只是为了确保我也想添加我的解释。

为了使对象(对于您的情况)是线程安全的,它必须:

  • 是不可改变的
  • 安全发布

永恒 - 你做到了。 设置后无法修改栏。 这里非常明显。

安全发布 根据示例,代码未安全发布。 因为bar不是final,所以编译器可以根据需要自由重新排序。 在写入bar 之前 ,编译器可以发布(写入主存储器)对Foo实例的引用。 这意味着bar为null。 因此, 首先将对Foo的引用写入主存储器, 然后发生写入条形码。 在这两个事件之间,另一个线程可以将过时条视为null。

如果你添加final,JMM将保证:

保证最终字段的值对访问构造对象的其他线程可见。

或者,最终字段可防止重新排序。 因此,使变量最终将确保线程安全。

从评论中发布的链接

class FinalFieldExample { 
    final int x;
    int y; 
    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3; 
        y = 4; 
    } 

    static void writer() {
        f = new FinalFieldExample();
    } 

    static void reader() {
        if (f != null) {
            int i = f.x;  // guaranteed to see 3  
            int j = f.y;  // could see 0
        } 
    } 
}

一个线程可以调用writer() ,另一个线程可以调用reader() reader()中的if条件可以求值为true,但是因为y不是最终的, 对象初始化可能还没有完全完成 (所以对象尚未安全发布),因此int j = 0可能会发生,因为它没有已初始化。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM