经过大量的搜索,我发现了volatile关键字的多个定义。
概念1:
某些网站说,它是线程安全的,因为线程在存储volatile关键字的主内存上起作用并对其进行修改,而无需将其拉到线程堆栈空间。
概念2:
有人说,它不是线程安全的,因为它会导致线程竞争状态。作为,线程将volatile变量拉到堆栈空间,对其进行修改,然后立即将其放回主内存。但是,在另一个线程之间可以对volatile变量起作用并采取行动。因此,这种方式会失去一些价值。
哪个概念正确?
答案 0 :(得分:4)
volatile
既不是线程安全的,也不是非线程安全的。
volatile
对单个字段保证atomicity,因此它可用于单个线程安全的读取或单个线程安全的写入。
但是,如果您要执行由读取和写入(整体上可以理解)组成的线程安全操作,则volatile
并不能提供线程安全,因为volatile
保证了原子性仅用于单个操作(读或写)。
总结:
volatile
就足够了(如果没有volatile
,其他线程可能永远不会甚至看不到书面价值)volatile
是不够的;相反,您可以使用:
答案 1 :(得分:3)
这篇IBM文章很好地总结了这一点:
易失性变量共享已同步的可见性功能,但是 没有一个原子性特征。这意味着线程将 自动查看易失性变量的最新值。 它们可用于提供线程安全性,但仅在 受限制的情况:在情况之间不施加约束的情况 多个变量或变量的当前值与其变量之间 未来价值。因此,仅凭挥发性就不足以实施 计数器,互斥量或任何具有不变量相关的类 多个变量(例如“ start <= end”)。
来源:https://www.ibm.com/developerworks/java/library/j-jtp06197/
与StackOverflow相关的问题:Do you ever use the volatile keyword in Java?
答案 2 :(得分:2)
concept 1
很容易理解,但是不正确。 volatile
是JMM提供的某种同步规范,与实现无关。此外,它不能在所有情况下保证线程安全。
使用易失性变量可降低内存一致性的风险 错误,因为任何对volatile变量的写入都会建立一个 发生于事前的关系,以及随后的相同阅读 变量。
这意味着对volatile变量的更改总是 对其他线程可见。而且,这还意味着 线程读取一个可变变量,它不仅看到最新的变化 易变,但也导致了代码的副作用 改变。
线程安全用法:
1. int value = 1;
2. thread1 executes: value = 2;
3. when thread2 reads value, it must be 2
线程的不安全用法:
1. int value = 1;
2. thread1 executes: value++;
3. when thread2 reads value, it could be 1 or 2, because value++ is not atomic.
答案 3 :(得分:2)
在这里,我经过全面的Google搜索后了解了什么:
•Volatile关键字用于避免线程内部变量的本地副本。所有线程将从主内存访问volatile变量,对其进行更新,然后立即将其放回主m / m。
来自ibm.com::所有读写操作将直接对主m / m进行,而不是对寄存器或本地处理器高速缓存进行。
•易失变量不是线程安全的。如果多个线程尝试写入一个volatile变量,则会出现Race条件。
•每个线程都有一个单独的m / m空间,称为工作m / m,其中包含diff的值。用于执行操作的变量。执行完操作后,线程将变量的更新值复制到main m / m中,其他线程可以从那里读取最新值。但是,如果变量是非易失性的,则新值可能不会立即刷新到主m / m。其他线程可能无法读取更新的值。
•同步提供互斥和可见性。但是volatile仅提供可见性。
答案 4 :(得分:0)
仅使用volatile不会使关键部分成为线程安全。 只是它以两种方式帮助我们。
线程可以拥有内存位置值的副本(可能已加载到注册表或缓存)。当访问volatile变量时,它将始终从主内存中读取。
java编译器不会重新排列这些变量的使用顺序(特别是在同步范围内)。
这意味着,要编写线程安全代码,我们可能必须使用volatile,但仅使用volatile并不会带来任何好处。