1

只想确认一下。我正在关注 Java Concurrency in practice book。当谈到安全发布时,尤其是使用 final 时,我很清楚首先引用将对所有其他线程可见,其次发布对象的状态对任何其他线程都是可见的,但这里的问题是,如果引用的数组元素是否保证在发布状态时可见?(当然只要没有人修改这些数据对象)。

例子:

@Mutable
public class NotThreadsafeDataObject {

    private String message;

    public NotThreadsafeDataObject (String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

现在让我们安全地发布一组可变对象:

public class Publish {

    public final NotThreadsafeDataObject[] publish;

    public Publish() {
        publish = new NotThreadsafeDataObject[] { new NotThreadsafeDataObject("one"), new NotThreadsafeDataObject("two")};

    }

}
4

2 回答 2

0

我很确定您仍然可以修改数组中各个可变对象的值。IE

publish[0].setMessaage("Hello");

会工作得很好。而且我相信你可以从你的数组中删除对象。它是 Array 引用,因为它已声明,所以无法更改final。如果您想拥有完全不可变的集合,我将使用声明为 final 的 List,然后创建一个新的单独 List,填充它,然后使用方法public static List unmodifiableList(List list)将其分配给您的最终列表:

ublic class Publish {

    public static final List<NotThreadsafeDataObject> publish;

    static {
        init();
    }  

    private static void synchronized init() {
       List<NotThreadsafeDataObject> list = new ArrayList<>();
       list.add(new NotThreadsafeDataObject("one");
       list.add(new NotThreadsafeDataObject("two");
       publish = Collections.unmodifiableList(list);
    }  
}

这使得防弹列表完全不可变,既不能更改对其的引用,也不能更改其内容。

于 2017-04-03T16:09:00.540 回答
0

如果我们用“Java Concurrency in Practice”中介绍的术语说话,那么您的数组是一个“有效不可变”的对象。对于这样的对象,安全发布对于不破坏内部状态总是必要的。所以你的代码没问题,因为你使用的是安全发布。更具体地说,“final”关键字内存语义保证访问 final 字段的线程将看到在写入该字段之前发生的所有事情(“happen-before”被建立)。

于 2017-04-03T15:49:00.500 回答