volatile关键字是什么
在并发编程中synchronized是阻塞式同步,在线程竞争激烈的时候,它会升级为重量级锁,而volatile是Java虚拟机提供的最轻量级的同步机制。
在Java内存模型当中,告诉我们,各个线程会将共享变量从主存中拷贝到工作内存,然后执行引擎会基于工作内存中的数据进行操作处理。
那在线程的工作内存进行操作后何时会写的主存中?这个时机对普通变量是没有规定的,而针对volatile修饰的变量Java虚拟机给予了特殊的约定。
volatile 这个变量具备两种特征:
1. 一种是保证该变量对所有的线程可见的,在一个线程修改了变量值之后,新的值对于其他线程是可以理解获取的。 2. 一种是volatile禁止指令重排,即volatile变量不会被缓存在寄存器中或者其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。 3. 但volatile不能保证对变量操作的原子性。
volatile实现可见性和有序性
因为在访问volatile 修饰的变量的时候,是不会执行加锁操作的,所以也意味着不会执行线程阻塞,因此volatile变量修饰的是一种比synchronized关键字更轻量级的同步机制,volatile 主要是适用于一个变量被多个线程共享,多个线程均可针对这个变量执行赋值或者读取操作。
在有很多线程对普通变量进行读写的时候,每个线程都首先需要将数据从内存中复制到CPU的缓存当中,如果计算机中有多个CPU,则线程可能都在不同的CPU中执行,这就意味着每个线程都需要将同一个数据复制到不同的CPU cache当中,这样在每个线程对同一个变量的数据做了不同的处理后就可能存在数据不一致的情况。
如果将变量声明了volatile,那么JVM就能保证每次读取变量时能直接从内存中读取,跳过CPU Cache这一步,有效的解决了多线程数据同步的问题。
下面我们就用代码演示一下volatile关键字修饰的可见性。
所以我们在这稍作修改,给我们需要读的变量添加上volatile变量,将它变为在其他线程是可读的。
代码:
public class ThreadDemo implements Runnable{
//volatile修饰的变量,在这表示一个线程中被修改后,对其它线程立即可见
private volatile boolean flag = false;//共享数据
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.flag = true;//让一个线程修改共享变量值
System.out.println(this.flag);
}
public boolean getFlag() {
return flag