volatile
关键字。由于不是很熟悉它,我找到了这篇说明文章。鉴于该文章详细解释了关键字的相关内容,您是否曾经使用过它,或者是否可以想象出可以正确使用该关键字的情况?
volatile
关键字。由于不是很熟悉它,我找到了这篇说明文章。volatile
具有内存可见性的语义。基本上,volatile
字段的值在写操作完成后对所有读取者(尤其是其他线程)变得可见。没有 volatile
,读取者可能会看到一些未更新的值。
回答你的问题:是的,我使用一个 volatile
变量来控制某些代码是否继续循环。循环测试 volatile
值,如果它为 true
,则继续。可以通过调用“停止”方法将条件设置为 false
。当循环在执行停止方法后测试该值时,它会看到 false
并终止。
我强烈推荐的书籍 "Java Concurrency in Practice" 对 volatile
进行了很好的解释。这本书是由写了 IBM 文章的同一人编写的(实际上,在那篇文章底部引用了他的书)。我的使用 volatile
是他的文章所称的“模式 1 状态标志”。
如果您想更深入地了解volatile
是如何工作的,可以查阅Java内存模型。如果您想超越这个水平,请查看好的计算机体系结构书籍,比如Hennessy&Patterson并阅读关于高速缓存一致性和高速缓存一致性的内容。
“...volatile修饰符保证读取字段的任何线程都将看到最近写入的值。” - Josh Bloch
如果您考虑使用volatile
,请阅读处理原子行为的java.util.concurrent
包。volatile
和synchronized
关键字? - ptkatovoid
又有public
关键词”。 - DavidSvolatile
在某种程度上类似于类上的static
关键字,可以让类的多个实例共享同一个变量/属性。 - Arumanstatic
变量,那么它可能还必须是volatile
,这两者是无关的。 - Nom1fan挥发性(vɒlətʌɪl): 在常温下容易蒸发
volatile
的重要点:
synchronized
和volatile
以及锁来实现同步。synchronized
变量。使用synchronized
关键字与变量是非法的,并将导致编译错误。在Java中,可以使用java volatile
变量代替使用synchronized
变量,这将指示JVM线程从主内存读取volatile
变量的值,而不会将其缓存在本地。volatile
关键字。volatile
的示例用法:
public class Singleton {
private static volatile Singleton _instance; // volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized (Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
_instance
变量设为volatile
,那么创建Singleton
实例的线程就无法与其他线程通信。因此,如果线程A正在创建Singleton实例,刚刚完成创建,而CPU出现了问题等,所有其他线程将无法看到_instance
的值不是null,并且它们将认为它仍然被赋为null。_instance
的值也不会在主内存中更新。使用Java中的Volatile关键字,Java自己处理这个问题,这样的更新将被所有读取线程看到。
结论:
volatile
关键字也用于在线程之间通信内存内容。
没有使用volatile的示例用法:
public class Singleton {
private static Singleton _instance; //without volatile variable
public static Singleton getInstance() {
if (_instance == null) {
synchronized(Singleton.class) {
if (_instance == null)
_instance = new Singleton();
}
}
return _instance;
}
}
volatile
用法:
快速失败的迭代器通常使用列表对象上的 volatile
计数器来实现。
Iterator
时,当前计数器的值将嵌入到 Iterator
对象中。Iterator
操作时,该方法将比较两个计数器的值,并在它们不同时抛出 ConcurrentModificationException
。故障安全迭代器的实现通常是轻量级的。它们通常依赖于特定列表实现数据结构的属性。没有一般模式。
private static final Singleton _instance;
。 - Chris311volatile
非常有用,可以停止线程。
虽然你不应该编写自己的线程,Java 1.6有很多好用的线程池。但是如果你确定需要一个线程,你将需要知道如何停止它。
我用于线程的模式是:
public class Foo extends Thread {
private volatile boolean close = false;
public void run() {
while(!close) {
// do work
}
}
public void close() {
close = true;
// interrupt here if needed
}
}
在上面的代码片段中,读取close
的线程与调用close()
的线程不同。没有使用volatile关键字,运行循环的线程可能永远看不到对close的更改。volatile
关键字声明的变量具有两个特性,使其变得特殊。
如果我们有一个volatile变量,它不能被任何线程缓存在计算机(微处理器)的高速缓存中。所有访问都来自主内存。
如果在一个volatile变量上有写操作,并且突然请求进行读操作,则保证写操作将在读操作之前完成。
以上两点特性推断出来:
另一方面,
volatile
关键字是维护一个共享变量的理想方式,该变量有'n'个读者线程和仅一个写者线程来访问。一旦添加了volatile
关键字,就完成了。没有其他与线程安全相关的开销。相反地,
我们不能仅使用volatile
关键字来满足具有多个写者线程访问的共享变量。
使用volatile
的一个常见例子是将volatile boolean
变量用作线程终止标志。如果您已经启动了一个线程,并且希望能够安全地从不同的线程中断它,可以让该线程定期检查一个标志。要停止线程,请将标志设置为true。通过将标志设置为volatile
,您可以确保检查它的线程在下一次检查时看到它已经被设置,而无需甚至使用synchronized
块。
Java Volatile
volatile
-> synchronized
[关于]
volatile
声明告诉程序员该值始终是最新的。问题在于该值可以保存在不同类型的硬件内存中。例如,它可以保存在 CPU 寄存器、CPU 缓存、RAM 中... CPU 寄存器和 CPU 缓存属于 CPU,无法共享数据,而 RAM 则在多线程环境下提供了帮助。
volatile
关键字表示一个变量将会被直接从/写入 RAM 内存。它有一些计算足迹。
Java 5
扩展了 volatile
,支持 happens-before
[关于]
对 volatile 字段的写操作 happens-before 每个后续对该字段的读取操作。
Read is after write
volatile
关键字不能解决 竞态条件
[关于] 的问题,要解决这个问题需要使用 synchronized
关键字[关于]
因此,只有一个线程写入,其他线程只读取volatile
值时才是安全的。
没有人提到长整型和双精度浮点型变量类型的读写操作处理。对于引用变量和大多数原始变量,读写是原子操作,但对于长整型和双精度浮点型变量类型,则必须使用volatile关键字才能实现原子操作。@link
是的,当您希望多个线程访问可变变量时,必须使用 volatile。这并不是非常常见的用例,因为通常您需要执行不止一个原子操作(例如,在修改变量之前检查变量状态),在这种情况下,您将使用 synchronized 块。
在我的看法中,除了停止线程之外,使用volatile关键字的另外两个重要场景是:
volatile
特性,这个特性随着 JSR 133 中定义的新 Java 内存模型而来:当一个线程读取一个volatile
变量时,它看到的不仅仅是一些其他线程上最后写入的值,还包括在那个写入volatile
的时间点上可见的其他变量的所有写操作。请参考 这个答案 和 这个参考资料。 - Adam Zalcman