详解Voliate

发布时间:2023-05-24

一、基础概念

在多线程并发操作中,多个线程同时对同一变量进行读写操作,很容易发生线程安全问题。Java语言提供了一种轻量级同步机制——volatile关键字,它可以确保多个线程之间对该变量进行操作时的可见性和有序性。 当一个变量被定义为 volatile 类型后,它表示该变量是“易变的”,也就是每次获取该变量的值时,都直接从内存中读取,而不是从线程的本地缓存中读取。同时,对该变量的操作不会执行处理器重排序优化,即操作时会按照程序中的顺序进行执行。

二、用途实例

1、双重检查锁定实现单例模式

public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

由于 instance 变量使用了 volatile 修饰,所以它保证了对该变量的所有操作都具有原子性和可见性,任何时刻,不管多少个线程同时访问该变量,都能保证每个线程对该变量的读取都是最新的。

2、线程间的通信

volatile 关键字可以实现线程之间的通信,即当值变化时其他线程可以立即感知到。以下代码演示使用 volatile 实现一个 boolean 类型的标志位:

public class ThreadCommunication {
    private volatile boolean flag;
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    public void work() {
        while (!flag) {
            // 等待 flag 变为 true
        }
        // 执行后续操作
    }
}

在多线程环境下调用 setFlag(true) 方法,即可实现线程的唤醒,并执行后续操作。

3、提高性能

在并发编程中,为了减少锁的竞争,通常会将一些变量定义为 volatile 类型。因为 volatile 变量在读写操作时,由于不涉及到锁的释放和获取,所以相对的性能更高。

三、注意事项

1、volatile 仅保证可见性和有序性,无法保证原子性。 2、volatile 对变量的写操作不依赖于变量的当前值,即多个线程对同一个 volatile 变量进行操作时,操作之间不会互相影响。 3、不要将所有变量都定义为 volatile 类型,应该根据业务需求进行选择。 4、对 volatile 变量的读写操作不能复合成更大的原子操作。 5、volatile 关键字不能保证数据的线程安全性,只能保证数据可见性。

四、总结

在多线程编程中,采用 volatile 关键字可以实现变量的可见性和有序性,从而避免出现线程安全问题。但是在使用 volatile 时,需要注意该关键字的使用场景和注意事项,以免出现思路混乱和程序错误。