如何理解Java语言规范挥发性的例子吗?

蒂姆:

我想,例如在Java规范挥发是一个小错误。

在8.3.1.4。挥发性字段,它说

class Test {
    static int i = 0, j = 0;
    static void one() { i++; j++; }
    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }
}

...然后方法2可以偶尔打印对于j大于i的值大的值,这是因为例子包括没有同步,并且根据规则解释in§17.4,i和j的共享值可能的被更新了订购。

我想,即使这些更新是为了,方法二可能仍会看到Ĵ比我大的,因为System.out.println("i=" + i + " j=" + j)不是原子的,我为j前阅读。

方法二是像相同

read i
read j

因此,它是可能的

read i
i++
j++
read j

在这种情况下两个方法见J A值大于i,但是更新是并不过分的。

所以出来的顺序是不希望看到j中的唯一理由>

它应该是System.out.println("j=" + j + " i=" + i);

这一次失灵,就是看J>时我的唯一原因

霍尔格:

这些例子是不是“有点不对劲”了。

首先,你是正确的,即使没有重新排序,j可能会出现大于i在这个例子。这是即使在后来承认同一个例子

另一种方法是申报ijvolatile

class Test {
    static volatile int i = 0, j = 0;
    static void one() { i++; j++; }
    static void two() {
        System.out.println("i=" + i + " j=" + j);
    }
}

这允许方法one和方法two将被并行地执行,而是访问到共享值的保证ij它们出现的每个线程的程序文本的执行期间发生的准确发生多次,并且以完全相同的顺序。因此,对于共享值j永远不会比,对于大i的,因为对每个更新i必须在共享值被反射为i使更新前j发生。这是可能的,但是,这种方法的任何给定调用two可能会为观察值j是远远大于所观察到的值i,因为方法one时,方法可能被执行的时刻之间多次two获取的价值i的时刻和方法two获取的价值j

当然,这是深奥说“ 的共同价值j是永远不会比更大的i ”,只是说对下一句“ 这是可能的... [于]观察值j是远远大于所观察到的值i ”。

所以j是永远不会大于i,当观察到,除了大于i难道这就是地说,“大一些”是不可能的?

当然不是。这种说法是没有意义的,似乎是试图从“观测值”,而实际上是不同的一些客观事实,如“共享价值”的结果,是在一个程序只观察行为。

这是由错误的一句说明:

这允许方法之一,方法2被同时执行,但访问所述共享值的保证ij它们出现的每个线程的程序文本的执行期间发生恰好发生多次,并且以完全相同的顺序。

即使有volatile变数,也没有这样的保证。所有的JVM必须保证,就是观察到的行为并不矛盾的规范,所以当你调用one()一个循环千倍,例如,优化程序可能仍使用单位递增的千替换它,如果它可以排除另一个线程目睹这样的优化的存在(比从更高的速度推断其他)的可能性。

或者换句话说,有多少次的变量(相应地,它的内存位置)实际上是访问,不是观察到的,因此,没有规定。它不怎样都无所谓。所有这些问题给应用程序的程序员,是j可以大于i,变量是否声明volatile与否。

交换的顺序的读取ijtwo()可能使一个更好的例子,但我认为,这将是最好的,如果JLS§8.3.1.2没有试图解释的意思volatile通俗,只是表示,根据规定特殊语义到内存模型和它留给JMM解释它在形式上正确的方式。

程序员不只是通过阅读8.3.1.4应该掌握的并发,所以例子是没有意义在这里。(在最好的情况下,最坏的情况将造成一种印象,这个例子足以了解此事)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章