之前讲了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
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》