【问题标题】:Java publish safely with finalJava 使用 final 安全发布
【发布时间】:2013-11-14 21:05:44
【问题描述】:

只是为了确保。 我正在关注 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")};

    }

}

【问题讨论】:

  • 据我了解,final 表示(对于对象)引用不会改变。但是,该对象的内部状态可能仍会发生变化,并且仍然允许线程获取它们自己的这些内部缓存。 volatile 关键字防止线程保留自己的缓存
  • 被引用的对象及其引用的对象在发布后不会改变……按照惯例。我想知道使用 final 字段安全发布后数组内引用的可变对象的可见性。

标签: java multithreading visibility


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    会工作得很好。而且我相信你可以从你的数组中删除对象。不能更改的是数组引用,因为它被声明为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);
        }  
    }
    

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

    【讨论】:

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