繁体   English   中英

Java并发 - 发布不可变对象(Java Concurrency in Practice)

[英]Java Concurrency - Publishing Immutable Objects (Java Concurrency In Practice)

在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);
}

会有数据竞争吗? (这意味着线程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;
    }
}

Section16.3初始化安全性的保证允许在线程之间安全地共享正确构造的不可变对象而不进行同步,无论它们是如何发布的,即使使用数据争用发布也是如此。 (这意味着如果Resource是不可变的, unsafeLazyInitialization实际上是安全的。)

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

是的,你是对的,有数据竞争。

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

在JCIP中,作者认为不可变对象在发布时是安全的,因为您不必担心做出防御性副本等事情。

至于:

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

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

您的List<ImmutableObject> list容器对象不是不可变的。 因此,对它的add和get方法将不是线程安全的。 需要同步这些方法以便从多个线程进行并发访问。

您的问题表明您正在预期第5.3节 - 阻止队列和生产者消费者模式。 以下是使用阻塞队列的类似内容:

public class Blocking
{
   private BlockingQueue<ImmutableObject> queue = new ArrayBlockingQueue<ImmutableObject>(10);

   public void methodA() {
      queue.add(new ImmutableObject());
   }

   public ImmutableObject methodB() throws InterruptedException
   {
      return queue.take();
   }
   static class ImmutableObject
   {

   }
}

阻塞队列是高度可变的 - 但设计为线程安全,因此您可以使用它而无需额外的同步。 只要您传递的对象是不可变的,整个设计就是线程安全的。

在上面的示例中,methodB使用“take”,它将阻塞,直到调用methodA将某些内容放入队列中。 或者直到线程被中断,此时它将通过InteruptedException退出

是的,有确定的数据竞争机会。 这是一种情况:

虽然主题A是里面methodA ,然后线程B将被执行methodB ,没有保证methodA以前返回methodB 如果不幸methodB已经返回,而methodA是尚未恢复,将有较高几率获得IndexOutOfBoundsException

// thread A invokes this method first
public static void methodA () {
    //assume control is taking time at this point, while thread B already returned!!!

    list.add(new ImmutableObject());
}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM