Java volatile
上次修改时间:2024 年 7 月 16 日
在本文中,我们定义了 Java volatile 关键字,并展示了如何使用它。
Java 中的 volatile 关键字是一种变量修饰符,它告诉 Java 虚拟机 (JVM) 一个变量可以被多个线程访问和修改。
volatile 关键字解决了多线程程序中的可见性问题。它确保对变量所做的更改能立即对其他线程可见。
volatile 变量的值始终从主内存读取和写入到主内存。这可以防止线程看到缓存在 CPU 寄存器或缓存中的过期值。这对于多线程编程至关重要,因为多个线程可能同时访问同一个变量。换句话说,它确保每次读取 volatile 变量都直接从计算机的主内存读取(而不是从 CPU 缓存读取),并且每次写入 volatile 变量都写入到主内存(不仅仅是写入到 CPU 寄存器)。
要点
-
volatile确保其他线程对更改的可见性。 - 它不保证操作的原子性(不可分割性)。
-
volatile对于标志、计数器或其他只需要可见性的变量非常有用。 - 对于需要可见性和原子性的场景,首选 synchronized 块或方法。
Happens-Before 关系
Java 内存模型 (JMM) 中的一个关键概念是“happens-before”。这定义了所有线程必须看到的操作顺序。 对 volatile 变量的写入建立了与对同一变量的所有后续读取的 happens-before 关系。这意味着在 volatile 写入之前对其他变量所做的任何更改,在写入之后,对读取 volatile 变量的线程变得可见。
标志示例
在下一个示例中,我们有一个 worker,它会一直运行直到标志设置为 false。
class Worker implements Runnable {
private volatile boolean isRunning = false;
public void setRunning() {
isRunning = true;
}
public void stopTask() {
isRunning = false;
}
public boolean isRunning() {
return isRunning;
}
@Override
public void run() {
System.out.println("worker started");
while (isRunning) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("doing task " + System.currentTimeMillis());
}
System.out.println(isRunning);
System.out.println("worker ended");
}
}
void main() throws InterruptedException {
System.out.println("Main thread started");
final var worker = new Worker();
worker.setRunning();
// Thread to start the task
var starter = new Thread(worker);
starter.start();
Thread.sleep(2000);
// Thread to stop the task using the flag
var stopper = new Thread(() -> {
if (worker.isRunning()) {
worker.stopTask();
System.out.println("stopping task");
}
});
stopper.start();
starter.join();
// stopper.join();
System.out.println("Main thread ended");
}
isRunning 标志控制 Worker 类中 run 方法的执行。while 循环持续检查 isRunning 的值。 如果另一个线程修改了 isRunning 的值(例如,通过调用 stopTask),则该更改将立即对执行循环的线程可见。
如果没有 volatile,不同的线程可能拥有 isRunning 的自己的本地副本,从而导致数据不一致。
在我们的例子中,只有可见性很重要。 如果我们还需要确保操作的原子性,我们需要选择同步方法或其他工具来代替。
来源
在本文中,我们使用了 Java 中的 volatile 关键字。
作者
列出所有Java教程。