本文介绍了如何理解Java语言规范中的易失性示例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我认为Java规范中volatile的示例有点错误.

在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,因为System.out.println("i=" + i + " j=" + j)不是原子的,并且i在j之前被读取.

方法二与

相同

read i
read j

所以有可能

read i
i++
j++
read j

在这种情况下,方法二看到j的值大于i,但是更新不会乱序.

所以乱序并不是看到j> i

的唯一原因.

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

这次混乱是看到j> i

的唯一原因

解决方案

这些示例不仅仅是有点错误".

首先,您是正确的,即使在没有重新排序的情况下,在此示例中,j可能会显示为大于i.甚至稍后会在同一示例中确认:

当然,可以说" j的共享值永远不大于i 的共享值",只是在下一个句子" It可能……[观察] j的值远大于i 的值."

所以j从不大于i,除非观察到它比i大?是否应该说再大一点"是不可能的?

当然不是.该语句没有任何意义,似乎是试图将诸如共享值"与观察值"之类的客观事实区分开来的结果,而实际上,程序中只有可观察到的行为.

这用错误的句子来说明:

即使具有volatile变量,也没有这样的保证. JVM必须保证的是观察到的行为不会与规范相抵触,因此,例如,当您在循环中调用one()千次时,优化器可能仍将其替换为如果可以排除另一个线程见证这种优化的可能性(不是从更高的速度中得出),则原子增量为1000.

或者换句话说,变量(实际上是其存储位置)实际被访问的次数是不可观察的,因此未指定.无论如何都没关系.对于应用程序程序员而言,重要的是,无论变量是否声明为volatilej都可以大于i.

two()中交换ij的读取顺序可能是一个更好的示例,但是我认为,如果JLS§8.3.1.2不尝试解释其含义,那将是最佳选择.口语化了volatile,但只是说它根据内存模型,然后将其交给JMM来以形式上正确的方式进行解释.

程序员不应仅通过阅读8.3.1.4来掌握并发性,因此此处的示例毫无意义(最好的情况;最坏的情况是给人以示例足以理解问题的印象). /p>

I think example of volatile in Java specification is a little wrong.

In 8.3.1.4. volatile Fields, it says

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

I think even if these updates are in order, method two may still see j greater than i, since System.out.println("i=" + i + " j=" + j) is not atomic, and i is read before j.

method two is the same like

read i
read j

So it is possible that

read i
i++
j++
read j

In this case method two see a value for j that is greater than i, however updates are NOT out of order.

So out of order is not the only reason to see j > i

Should it be System.out.println("j=" + j + " i=" + i);?

This time out of order is the only reason to see j > i

解决方案

The examples are more than "a little wrong".

First, you are right that even without reordering, j may appear greater than i in this example. This is even acknowledged later in the same example:

Of course, it is abstruse to say "the shared value for j is never greater than that for i", just to say right in the next sentence "It is possible … [to] observe a value for j that is much greater than the value observed for i".

So j is never greater than i, except when it is observed to be much greater than i? Is it supposed to say that "a little greater" is impossible?

Of course not. This statement makes no sense and seems to be the result of trying to separate some objective truth like "the shared value" from "the observed value" whereas in fact, there is only observable behavior in a program.

This is illustrated by the wrong sentence:

Even with volatile variables, there is no such guarantee. All that the JVM must guarantee, is that the observed behavior doesn’t contradict the specification, so when you invoke one() thousand times in a loop, for example, an optimizer may still replace it with an atomic increment by thousand, if it can preclude the possibility of another thread witnessing the presence of such an optimization (other than deducing from the higher speed).

Or in other words, how many times a variable (resp. its memory location) is actually accessed, is not observable and hence, not specified. It doesn’t matter anyway. All that matters to an application programmer, is that j can be greater than i, whether the variables are declared volatile or not.

Swapping the order of the reads of i and j within two() might make it a better example, but I think, it would be best, if JLS §8.3.1.2 did not try to explain the meaning of volatile colloquially, but just stated that it imposes special semantics according to the memory model and left it to the JMM to explain it in a formally correct way.

Programmers are not supposed to master concurrency just by reading 8.3.1.4., so the example is pointless here (in the best case; the worst case would be creating the impression that this example was sufficient to understand the matter).

这篇关于如何理解Java语言规范中的易失性示例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-18 05:11