当前位置:  开发笔记 > 编程语言 > 正文

为什么使用volatile会产生长双原子

如何解决《为什么使用volatile会产生长双原子》经验,为你挑选了2个好方法。

我正在尝试学习Java中多线程使用的术语.所以如果我在下面的文字中使用了错误的定义,请纠正我:

我从不同的资源中发现了我

原子动作: 根据Java doc:

在编程中,原子动作是一次有效发生的动作.原子动作不能在中间停止:它要么完全发生,要么根本不发生.在动作完成之前,原子动作的副作用是不可见的.

这就是为什么读或写长变量或双变量不是原子的.因为它涉及两个操作,第一个32位和第二个32位读/写变量.另外,从上面的段落中我了解到,如果我synchronized在方法上使用它,它将使该方法成为原子(理论上讲).

易变变量:也来自Java Doc:

这意味着对volatile变量的更改始终对其他线程可见.更重要的是,它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用.

现在,根据Joshua Bloch的Effective Java第2版,请考虑以下关于volatile声明的书中提到的要点:

考虑以下:

// Broken - requires synchronization!
private static volatile int nextSerialNumber = 0;

public static int generateSerialNumber() {
    return nextSerialNumber++;
}

方法的状态由单个可原子访问的字段nextSerialNumber组成,该字段的所有可能值都是合法的.因此,不需要同步来保护其不变量.但是,如果没有同步,该方法将无法正常工作.

这是因为nextSerialNumber++它执行读取,增量,写入时不是原子的.

我的总结

所以,如果nextSerialNumber++不是原子的,需要synchronize.那么为什么以下是原子的并且不需要同步?

private static volatile long someNumber = 0;

public static int setNumber(long someNumber) {
    return this.someNumber = someNumber;
}

我不明白为什么使用volatile double或者long使其原子化?

因为volatile它确实是确保线程B是否尝试读取long线程A正在写入的变量,并且线程A只写了32位,那么当线程B访问资源时,它将获得32由线程A编写的位数.这不会使其成为原子,因为Java Doc中解释了术语atomic的定义.



1> Stop ongoing..:

我不明白为什么在double或long上使用volatile会使它成为原子?

在不使用volatile关键字的情况下,您可能会读取a的前32位doublelong由一个线程写入,而另一个32位由另一个线程写入,称为单词撕裂,并且显然不是原子的.

volatile关键字可以确保不会发生.您读取的64位值将是由一个线程写入的值,而不是由多个线程写入的某些Franken值.这意味着由于volatile关键字,这些类型变为原子.

volatile关键字不能进行动作等x++原子,而不管类型(64位或32位),因为它是一个复合操作(读+增量+写),而不是一个简单的写入.a中涉及的操作x++可以通过其他线程的操作进行交织.该volatile关键字不能作这样的混合操作的原子.

所以如果nextSerialNumber++不是原子的,需要同步.那么为什么以下是原子的并且不需要同步?

private static volatile long someNumber = 0;

public static int setNumber(long someNumber) {
    return this.someNumber = someNumber;
}

nextSerialNumber++ 需要同步,因为它是复合操作,因此不是原子操作.

this.someNumber = someNumber原则归功于this.someNumber存在volatile,并且赋值操作也是原子的,是一个单独的操作.因此无需同步.没有volatile,this.someNumber不能以原子方式编写,因此需要同步.


我认为这个答案非常令人困惑和误导。的确,如果不使用“ volatile”,您可能会被撕裂,但是您也可能以其他方式失败。认为单词撕裂是*问题,这是一种误导和混淆。volatile不仅仅确保不会发生单词撕裂,它还提供了针对*任何*可能的故障机制的特定保证,即使在我们一无所知的硬件上也是如此。

2> Stephen C..:

我不明白为什么在double或long上使用volatile会使它成为原子?

这就是原因.使用volatilea doublelong使它们成为原子,因为JLS这样说.

JLS(第17.7节)规定:

"写入和读取volatile的long和double值总是原子的."


注意:JLS是规范性的.就语言语义而言,javadoc是非规范的.Bloch的"Effective Java"甚至不是Oracle文档 - 它只是一个(未经授权的)评论.


@moamzia具体来说,*Effective Java*不是规范性引用.
推荐阅读
谢谢巷议
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有