当前位置: 首页 > 知识库问答 >
问题:

为什么Volatile变量不用于原子性

田志
2023-03-14

来自Javadocs

使用易失性变量降低了内存一致性错误的风险,因为对易失性变量的任何写入都与同一变量的后续读取建立了先发生后发生的关系。这意味着对易失性变量的更改始终对其他线程可见。

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

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

总之,我无法理解这一点。

如果两个线程都在读取和写入一个共享变量,那么仅为此使用Volt关键字是不够的。在这种情况下,您需要使用同步来保证变量的读写是原子的。

共有2个答案

余善
2023-03-14

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

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

当您编写同步块时,原子单元就是您放在块中的任何东西。

李新霁
2023-03-14

有很多目的可以很好地用于易失性-但也有很多目的不适用。例如,假设您有一个这样的字段:

private volatile int i;

两个线程都运行这个。i:读取此。然后向其写入。

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

AtomicInteger(以及其他原子)通过允许您在单个原子中同时读写来解决这类问题(≈

 类似资料:
  • 主要内容:可见性,原子性,举个例子首先要了解的是,volatile可以保证可见性和顺序性,这些都很好理解,那么它为什么不能保证原子性呢? 可见性 可见性与Java的内存模型有关,模型采用缓存与主存的方式对变量进行操作,也就是说,每个线程都有自己的缓存空间,对变量的操作都是在缓存中进行的,之后再将修改后的值返回到主存中,这就带来了问题,有可能一个线程在将共享变量修改后,还没有来的及将缓存中的变量返回给主存中,另外一个线程就对共享变量

  • 主要内容:可见性,原子性,举个例子首先要了解的是,volatile可以保证可见性和顺序性,这些都很好理解,那么它为什么不能保证原子性呢? 可见性 可见性与Java的内存模型有关,模型采用缓存与主存的方式对变量进行操作,也就是说,每个线程都有自己的缓存空间,对变量的操作都是在缓存中进行的,之后再将修改后的值返回到主存中,这就带来了问题,有可能一个线程在将共享变量修改后,还没有来的及将缓存中的变量返回给主存中,另外一个线程就对共享变量

  • 问题内容: 调用longjmp()后,如果自setjmp()调用以来其值可能已更改,则不应访问非非易失性合格的本地对象。在这种情况下,它们的值被认为是不确定的,访问它们是未定义的行为。 现在我的问题是,为什么在这种情况下volatile起作用?难道那个可变变量仍然不能使longjmp失败吗?例如,在下面的示例中,longjmp将如何正常工作?当代码在longjmp之后返回到setjmp时,loca

  • 为什么在Java中不是原子的? 为了更深入地了解Java我试图计算线程中的循环执行的频率。 所以我用了 在主课上。 我有两条线。 线程1:打印

  • 首先,我知道volatile不会使多个操作(如)成为原子操作。这个问题是关于单个读或写操作的。 我最初的理解是,volatile只是执行了一个内存屏障(即其他线程将能够看到更新的值)。 现在我已经注意到JLS第17.7节说volatile还提供了一个读取或写入原子。例如,给定两个线程,两个线程都将不同的值写入,那么x最终将恰好表示其中一个值。 我很好奇这怎么可能。在一个32位系统上,如果两个线程并

  • 问题内容: 当它适合使用原语(例如,或),而不是,或者,反之亦然? 问题答案: 可见性语义完全相同,当需要使用原子原语时,使用原子原语很有用。 例如: 可能在多线程环境中产生问题,因为变量可能会在两行之间变化。如果您需要测试和分配是原子的,则可以使用: