volatile关键字的作用是什么?

  • Post category:Java

答案:

什么是volatile关键字?

volatile是Java中的关键字,用于标记一个变量,表示该变量在多线程中是可见且不被缓存的。当一个变量被声明为volatile时,它的值更改后会立即更新到主内存中,并且每次读取该变量的值时都会从主内存中读取最新的值。

volatile关键字的作用是什么?

在多线程编程中,线程间的通信是非常重要的。为了使线程之间的通信正确有效,需要满足两个原则:

  1. 可见性:当一个线程修改了共享变量的值时,其他线程必须能够及时看到这个变量的最新值。

  2. 原子性:当多个线程对共享变量进行操作时,操作的顺序和操作结果必须符合预期。

而volatile关键字可以保证线程之间的可见性,从而防止多线程编程中出现的线程安全问题。

如何使用volatile关键字?

为了使用volatile关键字,需要按照以下步骤进行:

  1. 将共享变量声明为volatile类型。

  2. 在需要更新共享变量的代码中,使用volatile关键字进行标记。

示例一:使用volatile保证变量的可见性

public class VolatileExample {
    private volatile boolean flag = false;

    public void setFlag() {
        this.flag = true;
    }

    public void printFlag() {
        while(!flag) {
            System.out.println("flag is false");
        }
        System.out.println("flag is true");
    }
}

在上面的代码中,flag是一个共享变量,用于标记一个线程是否已经结束。setFlag()方法用于更新flag的值,printFlag()方法用于输出flag的值。

如果不使用volatile关键字,可能出现以下情况:

  1. 线程A调用setFlag()方法,更新flag的值为true。

  2. 线程B调用printFlag()方法,由于flag的值被缓存在线程B的本地内存中,所以线程B可能会一直输出“flag is false”,无法看到线程A的修改。

但是如果将flag标记为volatile类型,那么就可以保证线程B能够及时看到线程A对flag的修改,从而保证程序的正确性。

示例二:使用volatile防止指令重排序

public class Singleton {
    private volatile static Singleton instance;

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

在上面的代码中,Singleton是一个单例类,getInstance()方法用于获取该类的唯一实例。

如果不使用volatile关键字,可能会出现以下情况:

  1. 线程A调用getInstance()方法,发现instance为null。

  2. 线程A进入synchronized代码块,开始创建Singleton实例。

  3. 线程A执行完Singleton的构造函数,将instance指向该实例。

  4. 由于指令重排序的原因,instance = new Singleton()可能会被重排到3的后面执行。

  5. 线程B调用getInstance()方法,发现instance不为null,直接返回instance,但此时instance并未完成初始化。

  6. 程序出现异常。

但是如果将instance标记为volatile类型,那么就可以防止这种情况的发生,保证程序的正确性。

总结

volatile关键字可以保证共享变量的可见性和防止指令重排序,是多线程编程中非常重要的关键字。对于具有共享状态的变量,建议使用volatile关键字来标记,以保证程序的正确性。