可见性:在多线程的环境下,一个线程对共享变量的修改,其他线程可以看到变量修改后的值。
验证可见性demo:
public class TestVolatile extends Thread {
volatile boolean flag;
@Override
public void run() {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
//子线程停顿3秒后,将flag修改为true
flag = true;
System.out.println(Thread.currentThread().getName() + "线程将flag修改为:" + flag);
}
public static void main(String[] args) {
TestVolatile testVolatile = new TestVolatile();
testVolatile.start();
//如果flag为false,主线程一直循环判断,直到flag为true,停顿1秒,输出修改以后的flag值
while (true) {
if (testVolatile.flag) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "线程读取到flag被改了");
break;
}
}
}
}
代码执行结果:
Thread-0线程将flag修改为:true
main线程读取到flag被改了
如果不加volatile关键字,当我们修改flag以后,主线程不会读到修改以后的值,程序会一直处于循环中,为什么会出现这种情况?先看一下下面这张图
JMM(JAVA内存模型):他说一个抽象的概念,并不真实存在,他描述的是一组规范,通过该规范定义了各个变量的访问方式。
由于JVM运行程序的实体是线程,每个线程在创建时,JVM都会分配一个单独的工作内存,不同线程之间不能访问对方的工作内存呢,线程间通过主内存来进行通信,所有变量都会定义在主内存中,如果线程对某一个变量进行修改,线程需要先将主存中的变量拷贝到工作内存中,操作完成后,再同步到主内存。因为工作内存中的变量会放入CPU的高速缓存中,而主内存的变量就在物理内存中,这样可以提高速度。
上面的代码执行流程为:
1,线程启动以后,各个线程都将主存变量flag=false读到自己的工作内存
2,子线程启动以后,停顿3秒,将变量修改为true,此时主线程进入while(true)循环,因为flag为false,所以一直循环
3,子线程修改以后,立即将该修改同步到主内存,此时主线程停顿1秒,读取到修改以后的值。