Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过Java volatile一次性安全发布_Java_Volatile - Fatal编程技术网

通过Java volatile一次性安全发布

通过Java volatile一次性安全发布,java,volatile,Java,Volatile,在本教程()中,Java的volatile声明如下: public class BackgroundFloobleLoader { public volatile Flooble theFlooble; public void initInBackground() { // do lots of stuff theFlooble = new Flooble(); // this is the only write to theFlooble

在本教程()中,Java的volatile声明如下:

public class BackgroundFloobleLoader {
    public volatile Flooble theFlooble;

    public void initInBackground() {
        // do lots of stuff
        theFlooble = new Flooble();  // this is the only write to theFlooble
    }
}

public class SomeOtherClass {
    public void doWork() {
        while (true) { 
            // do some stuff...
            // use the Flooble, but only if it is ready
            if (floobleLoader.theFlooble != null) 
                doSomething(floobleLoader.theFlooble);
        }
    }
}
据说后台线程是从数据库加载的,所以我认为作者的意思是实例化
newflooble()
需要大量时间

引用:
如果theFlooble引用不稳定,doWork()中的代码将面临看到部分构造的Flooble的风险,因为它取消了对theFlooble引用的引用。


怎么可能呢?我本以为会是相反的结果。也就是说,如果没有volatile声明,调用
doWork
方法的线程将有可能延迟或根本看不到Flooble

这可能是由编译器重新排序引起的。编译器可以内联
Flooble
的构造函数,更改其字段的初始化顺序,并将引用分配给
Flooble
变量。 声明bloodle
volatile可防止此类重新排序

编译器可以内联Flooble的构造函数并更改其字段的初始化顺序,并将引用分配给Flooble变量

我在博客、帖子和许多其他地方看到过这种说法,但它直接与java语言规范相矛盾:

本质上说,除非出现任何异常,否则构造函数将在返回引用之前完成。如果在构造对象之前没有引用,则在任何地方都看不到部分构造的对象。如果你内联了构造函数,你最好确保没有其他人能看到这个引用,否则你就违反了规范

我所看到的一个程序集反编译似乎表明这是由一个古老的赛门铁克JIT编译器生成的——这不完全是官方的


如果有人能解释为什么一个现代的、经批准的OpenJDK编译器可以重新排序写入以公开对部分创建的对象的引用,以及为什么这与规范不矛盾,我会咬一口,但直到,这一切看起来都像是一堆基于其他编译器和规范经验的挥手概括(而且,请注意,我并不是说通过将this指针泄漏到外部类来揭示一个部分构造的对象——如果这样做,你只能怪你自己)。

你永远看不到它,看不到它,看不到它,看不到它处于不一致的状态。看来实例化必须完成(即使读取数据库需要很长时间)在分配引用之前。在这种情况下,我不明白为什么被引用的对象会处于不一致的状态。确切地说,您的期望是合理的期望,但遗憾的是,如果这是真的,Java将无法有效地扩展到大量并发CPU。如果不使用volatile或synchronized,Java optimises在单个CPU上使用的代码。这意味着其他CPU可能会看到也可能不会看到该CPU所做的数据更改。每次CPU在CPU内部本地更改数据时,它的运行速度都非常快。每次它必须共享该更改以便其他CPU可以看到这些更改时,它的速度都会减慢很多。我无法强调这会减慢多少速度n是。您可能会将上述解释为Java语言级别的指令。这可能会导致这种混淆,Java指令的边界与本机cpu指令的边界不匹配。这种不匹配,再加上速度优化,意味着所有猜测都将被取消,除非什么是可见的/不可见的在不使用synchronized/volatile的情况下在CPU之间共享数据时可见。我很惊讶。这种重新排序感觉几乎像是破坏,或者至少是一个优化错误。一开始可能是这样。但在研究硬件设计历史时,它开始变得很有意义。曾几何时,只要我加快时钟速度,“轻松获胜”不再可能了,为了从CPU中获得更高的性能,硬件人员必须越来越并行,并采取一些非常巧妙的手段。Java在将我们程序员与这些优化隔离开来方面做得非常出色……大多数时候都是如此。@Martin Thompson在他的博客上对此进行了大量讨论,这是一篇非常好的文章。如果您有时间,我建议结帐。这是提高人们对不同问题的认识的一个良好开端。@这不是一个破坏或错误,因为它是有文档记录的。内存模型只是程序员方面性能和简单性之间的折衷。所以我们必须尊重Java内存模型。也许我应该考虑的不是厌恶这样:如果我不使用volatile,我会引入可见性(发布延迟)问题和重新排序优化使情况变得更糟。因为我确实希望使用volatile来解决可见性问题,所以没有什么可担心的。我希望看到一个很好的答案。我的理解同意这个答案,但教程是由Brian Goetz编写的,他确实写了一本关于Java并发性的书。