Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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 为什么可变变量不是';t用于原子性_Java_Multithreading - Fatal编程技术网

Java 为什么可变变量不是';t用于原子性

Java 为什么可变变量不是';t用于原子性,java,multithreading,Java,Multithreading,从 使用易失性变量可以降低内存一致性的风险 错误,因为对易失性变量的任何写入都会建立 发生在与该对象的后续读取的关系之前 变量这意味着对可变变量的更改总是 对其他线程可见 如果对volatile变量所做的更改对任何其他线程都是可见的,那么为什么在多个线程写入该变量的情况下不能使用volatile变量呢。为什么volatile只用于一个线程正在写入或读取该变量,而另一个线程只在读取该变量的情况 如果更改总是对其他线程可见,那么假设线程B想要写入该变量,它将看到新值(由线程A更新)并更新它。当线程A

使用易失性变量可以降低内存一致性的风险 错误,因为对易失性变量的任何写入都会建立 发生在与该对象的后续读取的关系之前 变量这意味着对可变变量的更改总是 对其他线程可见

如果对volatile变量所做的更改对任何其他线程都是可见的,那么为什么在多个线程写入该变量的情况下不能使用volatile变量呢。为什么volatile只用于一个线程正在写入或读取该变量,而另一个线程只在读取该变量的情况

如果更改总是对其他线程可见,那么假设线程B想要写入该变量,它将看到新值(由线程A更新)并更新它。当线程A再次想要写入时,它将再次看到线程B更新的值并写入。这其中的问题在哪里

简言之,我无法理解这一点

如果两个线程都在读写共享变量,那么 仅使用volatile关键字是不够的。你需要使用 在这种情况下同步,以保证读写 变量的类型是原子的


有很多目的
volatile
可以很好地发挥作用,但也有很多目的不是这样的。例如,假设有这样一个字段:

private volatile int i;
两个线程都运行
++this.i
:读取
this.i
,然后写入

问题是,
++this.i
是一个易失性读取,然后是一个完全独立的易失性写入。在读和写之间可能会发生很多事情;特别是,您可能会遇到这样一种情况,即两个线程都在写入
i
之前读取它。净效应是
i
的值仅增加1,即使两个单独的线程都增加了它


AtomicInteger
(以及其他原子)通过允许在单个原子中同时读写来解决此类问题(≈(挥发性)步骤。(这是通过使用比较和交换指令来实现的,该指令仅在读取的值仍然是当前值的情况下执行写入。增量和获取方法只是运行一个循环,重试该操作,直到写入实际成功。)

volatile有很多用途可以很好地工作,但也有很多用途是它不能做到的。例如,假设有这样一个字段:

private volatile int i;
两个线程都运行
++this.i
:读取
this.i
,然后写入

问题是,
++this.i
是一个易失性读取,然后是一个完全独立的易失性写入。在读和写之间可能会发生很多事情;特别是,您可能会遇到这样一种情况,即两个线程都在写入
i
之前读取它。净效应是
i
的值仅增加1,即使两个单独的线程都增加了它

AtomicInteger
(以及其他原子)通过允许在单个原子中同时读写来解决此类问题(≈(挥发性)步骤。(这是通过使用比较和交换指令来实现的,该指令仅在读取的值仍然是当前值的情况下执行写入。增量和获取方法只是运行一个循环,重试该操作,直到写入实际成功。)

想想“原子性”是什么意思。这意味着,在一个线程中发生的两个或多个操作,就其他线程所知,似乎是作为一个原子单元发生的

因此,如果我声明一些
volatile int foobar
,并编写代码对其执行一些操作,编译器如何知道这些操作中的哪些应该是原子单元

当你写一个
同步的
块时,原子单位就是你放在块中的任何东西。

想想“原子性”是什么意思。这意味着,在一个线程中发生的两个或多个操作,就其他线程所知,似乎是作为一个原子单元发生的

因此,如果我声明一些
volatile int foobar
,并编写代码对其执行一些操作,编译器如何知道这些操作中的哪些应该是原子单元


当您编写一个
synchronized
块时,原子单位是您在块中放入的任何东西。

所有线程都不必“仅”读或写。读写器的角色可以是“流畅的”,并且可以有两个以上的线程参与此交换。如果一个线程正在向变量写入值,它什么时候会看到(读取)值?请澄清您的最后一段。@SotiriosDelimanolis,它不会看到,但会遇到它的更新值。所以它会写入更新后的值。@Thilo,这个So回答说应该读取一个值。啊,那就看这个。该语句引用了一种模式,在该模式中,读取和写入都应作为单个外部可见操作以原子方式完成。所有线程都不必是“仅”读取或写入。读写器的角色可以是“流畅的”,并且可以有两个以上的线程参与此交换。如果一个线程正在向变量写入值,它什么时候会看到(读取)值?请澄清您的最后一段。@SotiriosDelimanolis,它不会看到,但会遇到它的更新值。所以它会写入更新后的值。@Thilo,这个So回答说应该读取一个值。啊,那就看这个。该语句引用了一种模式,在该模式中,读取和写入都应作为单个外部可见操作以原子方式完成。这是一个很好的示例。问题不在于一个线程在读取字段时不知何故错过了另一个线程的更新(volatile确保了这一点)。问题是,该字段可以由另一个线程在