Volatile 关键字 线程安全
Volatile 关键字 线程安全
这个问题已经有答案了:
在进行了很多搜索之后,我发现了很多关于volatile关键字的定义。
概念1:
有些网站表示,它是线程安全的,因为线程作用于存储volatile关键字的主内存并直接修改它,而不是将其拉到线程堆栈空间中。
概念2:
有些网站表示,它不是线程安全的,因为它会导致线程竞争条件。当线程将volatile变量拉入栈空间进行修改后,立即将其放回主内存。但是,在此期间,另一个线程可以来操作volatile变量并采取行动。因此,这种方式可能导致某些值丢失。
哪一个概念是正确的?
admin 更改状态以发布 2023年5月22日
这篇IBM文章很好地总结了这一点:
易失性变量共享了同步的可见性特性,但没有原子性特性。这意味着线程将自动看到易失性变量的最新值。它们可以用于提供线程安全性,但只在一个非常有限的情况下:不会在多个变量之间或一个变量的当前值和其未来值之间强加约束的情况下。因此,单独使用易失性不足以实现计数器、互斥量或任何涉及多个变量相关不变量(例如"start <= end")的类。
来源:https://www.ibm.com/developerworks/java/library/j-jtp06197/
与之有关的StackOverflow问题:Do you ever use the volatile keyword in Java?
volatile
对于单个字段既不安全也不非线程安全。
volatile
保证了单个字段的原子性,因此可以用于单个线程安全的读取或单个线程安全的写入。
然而,如果您想执行由读取后跟写入组成的线程安全操作(将其视为整体),则单独使用 volatile
在这里并不提供线程安全性,因为 volatile
仅保证单个操作的原子性(无论是读取还是写入操作)。
总之:
- 如果您有一个字段,并且希望确保一个线程写入该字段后,其他线程可以立即读取已写入的值 - 使用
volatile
就足够了(如果不使用volatile
,其他线程可能永远看不到已写入的值) - 如果您有一个字段,需要先读取再写入(基于您刚刚读取的值写入,因此这个值之间不能进行任何操作) - 则单独使用
volatile
不足够;而应该使用:AtomicReference
、AtomicInteger
等。- 或使用 同步。