Java 并发 - 发布不可变对象(Java 并发实践)

ben*_*ben 3 java concurrency multithreading java-memory-model

在 Java Concurrency In Practice 中,作者表示

  1. 不可变对象可以通过任何机制发布
  2. 任何线程都可以安全地使用不可变对象,而无需额外的同步,即使不使用同步来发布它们。

是否意味着以下习语可以安全地发布不可变对象?

public static List<ImmutableObject> list = new ArrayList<ImmutableObject>();

// thread A invokes this method first
public static void methodA () {
    list.add(new ImmutableObject());
}

// thread B invokes this method later
public static ImmutableObject methodB () {
    return list.get(0);
}
Run Code Online (Sandbox Code Playgroud)

会有数据竞赛吗?(这意味着线程 B 可能无法看到线程 A 添加的列表中的不可变对象)

非常感谢。


更进一步,作者说如果Resource是不可变的,下面的代码是安全的。

@NotThreadSafe
public class UnsafeLazyInitialization {
    private static Resource resource;

    public static Resource getInstance() {
        if (resource == null)
            resource = new Resource();  // unsafe publication
        return resource;
    }
}
Run Code Online (Sandbox Code Playgroud)

第 16.3 节 初始化安全的保证允许正确构造的不可变对象在没有同步的情况下跨线程安全共享,无论它们是如何发布的,即使使用数据竞争发布也是如此。(这意味着unsafeLazyInitialization如果Resource是不可变的,那实际上是安全的。)

对于这个问题的第二部分,在另一个问题中详细讨论(点击这里

Ale*_*rlo 5

是的,你是对的,存在数据竞争。

只有ImmutableObject是不可变的并且可以在线程之间安全地共享List,但是您的没有这些相同的保证,因此在添加ImmutableObject和检索它之间存在数据竞争。

在 JCIP 中,作者的意思是发布不可变对象是安全的,因为您不必担心做诸如制作防御性副本之类的事情。

至于:

任何线程都可以安全地使用不可变对象,而无需额外的同步,即使不使用同步来发布它们。

这个语句意味着给定 2 个线程A,它们都通过任何方式获得了一个不可变对象,它们都可以使用 objectA而不必担心线程安全问题。