当一个变量被标记为volatile
时,表示这个变量可能会被多个线程同时访问,需要保证线程之间对该变量的读写操作是线程安全的。volatile
关键字的作用是告诉编译器,该变量不应该被优化或缓存,每次对该变量的访问都要从内存中读取或写入。
volatile
关键字通常用于线程间通信,特别是在对于某一个变量的修改在其他线程所需使用时,以确保其可见性和一致性。常见的使用场景有:
1.标志位变量
指示线程是否需要执行某个操作。其中,一个线程比如将一个flag设置为true,其他线程需要不断地监视这个变量,一旦flag为true时,就采取相应的操作。这时应该将flag的声明前加上volatile关键字,否则线程为了提高效率会优化读写,可能出现不同步的问题。
示例代码如下:
public class VolatileFlag extends Thread {
private static volatile boolean flag = false;
public void run() {
while (!flag) {
// do something
}
System.out.println("Flag has been set to true");
}
public static void main(String[] args) throws InterruptedException {
new VolatileFlag().start();
Thread.sleep(1000);
flag = true;
System.out.println("Flag has been set to true");
}
}
在上述代码中,我们通过将flag变量声明为volatile,确保了flag变量对于不同线程的修改是可见的,从而保证了线程之间的正确通信。
2.单例模式
单例模式的使用场景是一个对象需要在应用的生命周期内保持唯一,这时候可以利用静态的单例对象,在需要时创建,保证唯一性。使用volatile关键字可以确保该单例对象的正确性和一致性。
示例代码如下:
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之后,可以确保对单例对象的读取和写入操作对所有线程是可见的,保证了单例对象的正确性和一致性。
总之,volatile
关键字确保某一变量的正确性和可见性,适用于多线程环境下,不同线程对某一变量的读写操作需要经过同步处理的情况。但是需要注意的是,volatile
不能保证原子性,对于多个操作之间存在相互依赖的情况,需要使用其他的线程同步机制,例如synchronized
或Lock
。