【问题标题】:Is the safe publishing of final instance-variables transitive for non-final secondary references?对于非最终二级引用,最终实例变量的安全发布是否可传递?
【发布时间】:2015-12-17 18:11:51
【问题描述】:

我知道,在构造函数完成后,最终实例变量会安全地发布到所有线程。但是,我想知道如果最终实例变量包含对包含非最终实例变量的对象的引用,这是否仍然安全。在构造函数完成后,这个辅助的、非最终的实例变量永远不会改变。考虑以下示例:

public class NonFinalImmutable {
    private Iterable<String> list = Collections.unmodifiableList(Arrays
            .asList("foo", "bar", "foobar"));

    public Iterable<String> getList() {
        return list;
    }
}

public class FinalImmutable {
    private final NonFinalImmutable reference;
    private final String[] array;

    public FinalImmutable(NonFinalImmutable reference,
            String... arrayEntries) {
        this.reference = reference;
        this.array = arrayEntries;
    }

    public NonFinalImmutable getReference() {
        return reference;
    }

    public String[] getArray() {
        return array;
    }
}

private void execute() {
    new Thread() {
        @Override
        public void run() {
            useLater(construct());
        }
    }.start();
}

private FinalImmutable construct() {
    return new FinalImmutable(new NonFinalImmutable(), "asdf", "jklö");
}

private void useLater(FinalImmutable finalImmutable) {
    new Thread() {
        @Override
        public void run() {
            for (String s : finalImmutable.getReference().getList()) {
                System.out.println(s);
            }
            System.out.println();
            for (String s : finalImmutable.getArray()) {
                System.out.println(s);
            }
        }
    }.start();
}

在另一个线程中使用实例变量FinalImmutable.referenceFinalImmutable.array 的内容是否安全,即使它们包含非最终实例变量?

【问题讨论】:

    标签: java multithreading thread-safety final java-memory-model


    【解决方案1】:

    是的,在分配最终字段时会发生冻结操作。你应该阅读Aleksey Shipilëv's blog 它真的很有用。他在2014 blog entry

    中讨论了冻结操作语义

    这是它的正式规定。注意 w 可能不是 final 字段的写入,而 r2 不是 final 字段的读取。真正重要的是包含冻结动作 F、某个动作 a 和读取最终字段的 r1 的子链 — 一起使 r2 观察 w。

    注意两个新订单,取消引用订单和内存

    在博客中,他证明了 final 字段的写入发生在某些操作之前,而该操作又发生在后续的非最终字段读取 r2 之前。

    在您的示例中,由于您首先构造了非共享 NonFinalImmutable,因此最终分配应该冻结之前发生的写入。如果NonFinalImmutable 可以在外面访问,则所有赌注都关闭。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多