不变性和重新排序 [英] Immutability and reordering

查看:98
本文介绍了不变性和重新排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对接受的答案进行评论



这个问题产生的热量比我想象中的要多得多。一个重要的结论是,我从公共和私人讨论的并发性利益邮件列表的成员(即实际工作在实现这些事情的人):



如果你可以找到不破坏任何线程间发生先前关系的顺序一致的重新排序,它是有效的重新排序(即,符合程序顺序规则和因果关系要求)。



这是John Vint在他的回答中提供的。






strong>



下面的代码(Java Concurrency in Practice清单16.3)由于明显的原因而不是线程安全的:

  public class UnsafeLazyInitialization {
private static Resource resource;

public static Resource getInstance(){
if(resource == null)
resource = new Resource(); // unsafe publication
return resource;
}
}

但是,几个页面后,他们的状态:


UnsafeLazyInitialization 资源是不可变的。


p>


  • 如果 Resource 是不可变的,任何线程观察 / code>变量将看到它为空或完全构造(由于Java内存模型提供的最终字段的强大保证)

  • 但是,没有什么可以阻止指令重新排序:特别是 resource 的两个读取可以被重新排序(在中有一个读取,如果而在 return )。因此,线程可以在 if 条件中看到非空资源,但返回空引用(* li>


我认为 UnsafeLazyInitialization.getInstance() code> Resource 是不可变的。



注意:我需要一个参数回答而不是纯yes或no语句。






(*)以更好地了解我对重新排序的观点,此博客文章由杰里米·曼森,谁是并发的JLS的第17章的作者之一,解释String的哈希码是如何安全通过良性数据竞争发布,以及如何去除局部变量的使用可能导致hashcode不正确地返回0,因为可能的重新排序非常类似于上面描述的:


我在这里做的是添加一个额外的读:第二次读哈希,在返回之前。奇怪的是它的声音,和不可能发生,第一次读取可以返回正确计算的哈希值,第二次读取可以返回0!这在存储器模型下是允许的,因为该模型允许操作的大量重新排序。第二次读取实际上可以在你的代码中移动,以便你的处理器在第一次读取之前完成!



解决方案

混乱我认为你在这里是作者的意思是安全出版。他指的是非空资源的安全发布,但你似乎得到了。



你的问题很有趣 - 是否可能返回一个空的缓存值的资源?



是的。



编译器允许重新排序操作,例如

  public static Resource getInstance(){
Resource reordered = resource;
if(resource!= null){
return reordered;
}
return(resource = new Resource());
}

这不违反顺序一致性规则,但可以返回一个空值。



无论这是否是最好的实施方案,都是争论的问题,但是没有规则阻止这种类型的重新排序。


Comment on accepted answer

This question has generated much more heat than I woul dhave imagined. An important conclusion I drew from public and private discussions with members of the concurrency interest mailing list (i.e. people who actually work on implementing those things):

If you can find a sequentially consistent reordering that does not break any inter-thread happens-before relationship, it is a valid reordering (i.e. is compliant with the program order rule and causality requirement).

That's what John Vint has provided in his answer.


Original question

The code below (Java Concurrency in Practice listing 16.3) is not thread safe for obvious reasons:

public class UnsafeLazyInitialization {
    private static Resource resource;

    public static Resource getInstance() {
        if (resource == null)
            resource = new Resource();  // unsafe publication
        return resource;
    }
}

However, a few pages later, in section 16.3, they state:

UnsafeLazyInitialization is actually safe if Resource is immutable.

I don't understand that statement:

  • if Resource is immutable, any thread observing the resource variable will either see it null or fully constructed (thanks to the strong guarantees of final fields provided by the Java Memory Model)
  • however, nothing prevents instruction reordering: in particular the two reads of resource could be reordered (there is one read in the if and one in the return). So a thread could see a non null resource in the if condition but return a null reference (*).

I think UnsafeLazyInitialization.getInstance() can return null even if Resource is immutable. Is it the case and why (or why not)?

Note: I expect an argumented answer rather than pure yes or no statements.


(*) to better understand my point about reordering, this blog post by Jeremy Manson, who is one of the authors of the Chapter 17 of the JLS on concurrency, explains how String's hashcode is safely published via a benign data race and how removing the use of a local variable can lead to hashcode incorrectly returning 0, due to a possible reordering very similar to what I describe above:

What I've done here is to add an additional read: the second read of hash, before the return. As odd as it sounds, and as unlikely as it is to happen, the first read can return the correctly computed hash value, and the second read can return 0! This is allowed under the memory model because the model allows extensive reordering of operations. The second read can actually be moved, in your code, so that your processor does it before the first!

解决方案

The confusion I think you have here is what the author meant by safe publication. He was referring to the safe publication of a non-null Resource, but you seem to get that.

Your question is interesting - is it possible to return a null cached value of resource?

Yes.

The compiler is allowed to reorder the operation like such

public static Resource getInstance(){
   Resource reordered = resource;
   if(resource != null){
       return reordered;
   }
   return (resource = new Resource());
} 

This doesn't violate the rule of sequential consistency but can return a null value.

Whether or not this is the best implementation is up for debate but there is no rules to prevent this type of reordering.

这篇关于不变性和重新排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆