在java中,volatile是一种轻量级的同步机制,用来确保一个变量的更新能被及时的被其他线程看见,保证了变量的可见性。
作用:
1.保证可见性
在多线程环境下,线程通常会将变量的值缓存到cpu缓存中,而不是直接从主内存中读取。如果一个线程修改了变量的值,其他的线程可能无法立即的感知到这个变量的变化。使用volatile关键字修饰的变量,可以保证线程每次都会从主内存中读取到最新的值,而不是从缓存中读取,从而保证了内存的可见性。(开销变大,效率降低,但是准确性/逻辑的正确性变高)
2.禁止指令重排序
在多线程环境中,为了提高性能,编译器和处理器可能会对指令进行重排序。volatile关键字通过插入内存屏障,禁止某些类型的指令重排序,从而在多线程环境下保持一个代码执行的有序性。对于一个volatile变量的写操作会在该写操作之前的所有普通读写操作完成之后进行,对一个volatile变量的读操作会在所有普通读写操作开始之前进行。
public class volatileDemo { private static volatile boolean flag = false; public static void main(String[] args) { Thread t1 = new Thread(()->{ while(!flag){ } System.out.println("Derected flag change!"); }); Thread t2 = new Thread(()->{ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } flag = true; System.out.println("t2:flag set to true!"); }); t1.start(); t2.start(); } }
flag被volatile修饰,因此每个线程要访问它都会在主内存中来读取它的值。
volatile和synchronized的区别
1.volatile只能保证内存的可见性,不能保证操作的原子性。
2.synchronized既能保证内存的可见性又能保证原子性,它通过锁的机制使同一时刻只有一个进程/线程能执行同步代码块,避免竟态条件。
volatile的使用场景
1.用于控制线程之间的通信,如:停止线程、标志位……
2.适用于只需要保证一个变量的可见性,而不需要完整的同步机制的场景