Java中的volatile int是否是线程安全的?

sha*_*awn 53 java multithreading volatile thread-safety

intJava中的volatile是否是线程安全的?也就是说,可以安全地读取和写入而不锁定吗?

Jon*_*eet 66

是的,您可以从中读取并安全地写入它 - 但是您不能执行任何复合操作,例如安全地增加它,因为这是一个读取/修改/写入循环.还有关于它如何与访问其他变量进行交互的问题.

volatile的确切性质令人困惑(请参阅JLS内存模型部分以获取更多详细信息) - 我个人通常会使用它AtomicInteger作为一种更简单的方法来确保我做对了.

  • 你可以安全地增加`volatile int`,但你需要用一个完整的负载`AtomicIntegerFieldUpdater`替换`++`.(没有那么快,但如果访问由简单的读/写和/或内存开销占主导地位很重要,那么它可能很有用) (13认同)
  • 不要挑剔,但只有1个线程执行它时,一切都是线程安全的. (4认同)
  • 为了更全面地说明++问题,我发现http://jeremymanson.blogspot.com/2007/08/volatile-does-not-mean-atomic.html很好而且清晰. (2认同)
  • @npace:Sumit 正在谈论一个线程写入而另一个线程读取的场景。 (2认同)

aio*_*obe 6

[...]因为能够安全地读取和写入而不锁定?

是的,读取将始终导致最后一次写入的值(并且读取和写入都是原子操作).

易失性读/写在执行中引入了所谓的先发生关系.

来自Java语言规范第17章:线程和锁

写入易失性字段(第8.3.1.4节) - 在每次后续读取该字段之前发生.

换句话说,在处理volatile变量时,您不必使用synchronized关键字显式同步(引入先前发生的关系),以确保线程获取写入变量的最新值.

正如Jon Skeet指出的那样,volatile变量的使用是有限的,你通常应该考虑使用java.util.concurrent包中的类.


Sau*_*abh 6

Java 中对 volatile int 的访问将是线程安全的。当我说访问时,我指的是对其进行单元操作,例如 volatile_var = 10 或 int temp = volatile_var (基本上是使用常量值进行写入/读取)。java 中的 volatile 关键字确保了两件事:

  1. 读取时,您总是获得主内存中的值。通常出于优化目的,JVM 使用寄存器或更一般的术语本地内存来存储/访问变量。因此在多线程环境中每个线程可能会看到不同的变量副本。但是使其成为易失性可确保对变量的写入刷新到主内存并从主内存读取它,从而确保线程看到变量的正确副本。
  2. 对易失性的访问是自动同步的。因此 JVM 确保读/写变量时的顺序。

然而,Jon Skeet 正确地提到,在非原子操作 (volatile_var = volatile + 1) 中,不同的线程可能会得到意外的结果。