编程语言
首页 > 编程语言> > java – 最终实例变量的安全发布是否可传递给非最终二次引用?

java – 最终实例变量的安全发布是否可传递给非最终二次引用?

作者:互联网

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

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.reference和FinalImmutable.array的内容是否安全?

解决方法:

是的,在分配最终字段时会发生冻结操作.你应该阅读Aleksey Shipilëv’s blog它真的很有用.他讨论了2014 blog entry中的冻结动作语义

And here is how it is formally specified. Notice that w may not be the write of final field, and r2 is not the read of the final field. What really matters is that the subchain containing freeze action F, some action a, and r1 which reads the final field — all together make r2 observe w.

Notice two new orders, dereference order, and memory

在博客中,他证明最终字段的写入发生在某个动作之前,而某个动作又发生在随后的非最终字段读取r2之前.

同样在您的示例中,由于您首先构造一个非共享的NonFinalImmutable,因此最终赋值应该冻结之前发生的写入.如果NonFinalImmutable可在外部访问,则所有投注均已关闭.

标签:java,multithreading,thread-safety,final,java-memory-model
来源: https://codeday.me/bug/20190628/1313657.html