
之前讲了Volatile关键字的作用是确保可见性,这里列举 Volatile的使用场景,主要包含4种Volatile的使用场景@mikechen
1.多线程下的共享变量
当一个变量被多个线程共享时,为了保证线程之间对该变量的读写操作是安全的,需要使用 volatile 关键字来确保该变量的可见性和一致性。
如下所示:
public class VolatileExample {
private volatile boolean isRunning = true;
public void run() {
while (isRunning) {
// do some work
}
System.out.println("Thread stopped.");
}
public void stop() {
isRunning = false;
}
public static void main(String[] args) throws InterruptedException {
VolatileExample example = new VolatileExample();
Thread thread = new Thread(() -> example.run());
thread.start();
Thread.sleep(1000);
example.stop();
thread.join();
System.out.println("Main thread stopped.");
}
}
在这个例子中,使用volatile关键字确保了所有线程都能正确看到isRunning变量的最新值,如果没有使用volatile关键字,线程可能会缓存变量的旧值,导致while循环无法正确停止。
2.状态标志位
Volatile状态标志位常用于控制多个线程之间的操作流程,例如:通知线程停止或重新开始执行任务等。
如下所示:
public class Task implements Runnable {
private volatile boolean isRunning = true;
public void run() {
while (isRunning) {
// do some work
}
System.out.println("Thread stopped.");
}
public void stop() {
isRunning = false;
}
public void start() {
isRunning = true;
}
public static void main(String[] args) throws InterruptedException {
Task task = new Task();
Thread thread = new Thread(task);
thread.start();
Thread.sleep(1000);
task.stop();
Thread.sleep(1000);
task.start();
thread.join();
System.out.println("Main thread stopped.");
}
}
有时候我们需要一个状态标志位来控制程序的行为,比如线程的中断标志位、任务的完成状态等等。
在这种情况下,我们可以使用 volatile 关键字来保证状态标志位在不同线程之间的可见性。
3.双重检查锁定模式
双重检查锁定模式,全称Double Checked Locking Pattern,是一种常见的单例模式实现方式。
由于多线程环境下存在并发访问的问题,因此需要使用 volatile 关键字来确保单例对象的初始化操作的可见性和一致性。
如下所示:
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
// private constructor to prevent instantiation
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
由于使用了volatile关键字,所以在多线程环境下,任何线程都可以正确地看到instance变量的最新值,从而避免了线程安全问题。
4.高性能并发队列
在高性能的并发队列中,为了保证多线程操作的正确性,需要使用 volatile 关键字来确保队列头尾指针的可见性和一致性。
如下所示:
public class ConcurrentQueue<T> {
private volatile Node<T> head;
private volatile Node<T> tail;
public void offer(T value) {
Node<T> node = new Node<>(value);
if (head == null) {
head = node;
tail = node;
} else {
tail.next = node;
tail = node;
}
}
public T poll() {
Node<T> node = head;
if (node == null) {
return null;
}
T value = node.value;
head = node.next;
if (head == null) {
tail = null;
}
return value;
}
private static class Node<T> {
final T value;
volatile Node<T> next;
Node(T value) {
this.value = value;
}
}
}
以上就是Volatile使用场景详解,更多Volatile,请查看:Volatile的实现原理(看这篇就够了)
关于mikechen
mikechen睿哥,10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。