Volatile使用场景详解(4大使用场景)

Volatile使用场景详解(4大使用场景)-mikechen

之前讲了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面试题总结》,后台回复架构,即可获取《阿里架构师进阶专题全部合集

评论交流
    说说你的看法