volatile关键字-内存可见性
引出内存可见性问题的示例:
package com.atguigu.juc;
public class TestVolatile {
public static void main(String[] args) {
// 线程threadDemo修改共享变量的值
ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();
// main线程读取共享变量的值
while (true){
if (threadDemo.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
}
一直没有执行结束,像是main线程读取的共享变量的值一直都是false,导致main线程一直没有结束
内存可见性问题:
多个线程由于存在独立的缓存,因此在操作共享数据时彼此是不可见的(一个线程操作了共享变量之后,另一个线程看到的共享变量的状态还是改变之前的)
解决内存可见性问题:
通过同步锁可以解决内存可见性问题
package com.atguigu.juc;
public class TestVolatile {
public static void main(String[] args) {
// 线程threadDemo修改共享变量的值
ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();
// main线程读取共享变量的值
while (true){
// 同步锁能够保证main线程每次都能刷新缓存,去主存中读数据,保证每次读到的共享数据都是最新的
synchronized (threadDemo) {
if (threadDemo.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
}
class ThreadDemo implements Runnable {
private boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
}
volatile关键字:既想解决内存可见性问题,又不想通过加同步锁的方式解决(加锁后效率极低),因此出现了该关键字
当多个线程进行操作共享数据时,可以保证内存中的数据可见。(一个线程操作了共享变量之后,另一个线程能够马上看到共享变量状态的变化)
使用了volatile关键字,就相当于线程1是直接改的主存中的共享变量,main线程是实时从主存中读取的共享变量的值。
volatile关键字原理:内存栅栏
volatile关键字造成性能下降的原因:被volatile关键字修饰后,不能再进行重排序了
package com.atguigu.juc;
public class TestVolatile {
public static void main(String[] args) {
// 线程threadDemo修改共享变量的值
ThreadDemo threadDemo = new ThreadDemo();
new Thread(threadDemo).start();
// main线程读取共享变量的值
while (true){
if (threadDemo.isFlag()){
System.out.println("------------------");
break;
}
}
}
}
class ThreadDemo implements Runnable {
// 使用volatile关键字修饰共享变量
private volatile boolean flag = false;
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag = true;
System.out.println("flag=" + isFlag());
}
}
解决了内存可见性问题就相当于各个线程在直接操作主存中的数据
volatile和synchronized的比较:
volatile仅仅是更轻量级的一种同步策略
volatile不具备“互斥性”
volatile不能保证变量的“原子性”