引自;“Java线程”;关于volatile关键字的书

引自;“Java线程”;关于volatile关键字的书,java,volatile,Java,Volatile,我只是想知道是否有人能解释一下这句话的意思: 增量和 减量(例如,++和--)不能设置 用于可变变量,因为 这些操作是语法糖 用于装载、更改和存储 我认为增量和减量对于易失性变量来说应该可以正常工作,唯一的区别是每次读写时,都是从主内存而不是从缓存访问/写入 volatilevariable仅确保。这并不能保证。我想,这就是对这句话的解释。我想你是断章取义了 当然,++和--可以应用于可变变量。它们不会是原子的 而且由于volatile通常意味着必须以原子方式处理它们,这与目标背道而驰 ++和-

我只是想知道是否有人能解释一下这句话的意思:

增量和 减量(例如,
++
--
)不能设置 用于可变变量,因为 这些操作是语法糖 用于装载、更改和存储


我认为增量和减量对于易失性变量来说应该可以正常工作,唯一的区别是每次读写时,都是从主内存而不是从缓存访问/写入

volatile
variable仅确保。这并不能保证。我想,这就是对这句话的解释。

我想你是断章取义了

当然,
++
--
可以应用于可变变量。它们不会是原子的

而且由于
volatile
通常意味着必须以原子方式处理它们,这与目标背道而驰

++
--
的问题在于,它们可能感觉自己是原子,而实际上它们不是

执行
a=a+1
可以(在某种程度上)明确表示它不是一个原子操作,但有人可能(错误地)认为
a++
是原子操作。

不——使用“volatile”表示外部实体可以更改变量。
这通常是一些JNIC代码,或者是链接到某些硬件(如温度计)的特殊寄存器。Java不能保证所有体系结构上的所有JVM都能够在一个机器周期内增加这些值。所以它不允许你在任何地方做

Java语言规范没有针对
++
--
运算符的原子操作。换句话说,当您以以下方式编写代码时:

a++;
Java编译器实际发出的代码类似于下面的一组步骤(实际指令将根据变量的性质而变化):

  • 使用
    Load
    ing数据的操作之一将操作数加载到堆栈上
  • 复制堆栈上操作数的值(以便稍后返回)。这通常使用
    dup
    操作完成
  • 增加堆栈上的值。通常在VM中使用
    iadd
    操作完成
  • 返回值(在步骤2中获得)
  • 正如您所观察到的,VM中有多个操作,通常被认为是原子操作。VM只能确保原子性达到单个操作的级别。任何进一步的要求只能通过同步或其他技术来实现


    使用
    volatile
    关键字,允许其他线程获取变量的最新值;变量上的所有读取操作都将按每条指令返回最近更新的值。例如,如果变量
    a
    在前面的示例中是易变的,那么读取
    a
    值的线程在指令2和指令3之后读取
    a
    时会看到不同的值。使用
    volatile
    不能防止这种情况。它可以防止在指令2(例如)之后多个线程看到
    a的多个值的情况。

    Volatile不会在涉及多个步骤的操作中使用原子性

    从这个角度看,我正在读取一个值,这就是我所做的,读取操作是一个原子操作。这是一个单一的步骤,因此在这里使用volatile就可以了。但是,如果我读取该值并在写回之前更改该值,则这是一个多步骤操作,对于该volatile,它不会管理原子性


    增量和减量运算是多步的,因此使用volatile修饰符是不够的。

    根据我的理解,它说boolean volatile flag=false可以工作。这是否意味着flag=false是原子的?@Abidi:是的,对
    volatile
    变量的简单赋值始终是原子的(非
    volatile
    基本变量也是如此,除了
    double
    long
    ,顺便说一句)。@Vinet Reynolds,如果布尔flag=true;这是一个原子操作,那么我们为什么要让它不稳定呢?这是因为当线程切换发生时,线程B开始运行而不是A,并且B将标志的值设置为false,那么如果标志是易失性的,则只有A才能看到其更新的值(该值为false),否则它会看到其标志的现金版本(该值为true)?@Abidi,使用volatile可以确保如果一个线程要更新标志(为false),那么另一个读取标志值的线程(在更新之后)将看到更新后的值。这就是所谓的可见性;对变量所做的更改只有在原子操作之后才对其他线程可见。如果变量没有标记为volatile,那么是的,第二个线程将看到一个旧值,尽管进行了更新。您可以这样想,在某些允许的情况下,volatile可以用于同步对变量的访问,而无需获取锁。@Vinet Reynolds这很有帮助。只是想知道如果共享变量没有声明为volatile,那么读线程是否会尝试从内存中更新该变量的本地副本?@Abidi,这在很大程度上取决于编译器(JIT)执行的优化。与主存的同步仅在必要时发生-当进入或退出监视器时。如果我必须重写它,变量的读写可能会以不同于程序顺序的方式重新排序;volatile确保读取和写入按照源代码中描述的顺序进行,并且防止JVM使用本地缓存对这些变量进行操作。@Abidi,JLS声明这是“写入和写入”