解决线程间变量不可见性的方案
一、 背景
所有的实例变量和类变量都存储在主内存,但每个线程都有自己的工作内存,保留了主内存的共享变量的副本,线程修改的是共享变量,但是每个线程每次只能读取工作内存里的值,所以会导致变量不可见
示例代码:
public class visibilityDemo extends Thread{public static void main(String[] args) {visibilityTest vt=new visibilityTest();vt.start();while(true){if(vt.isFlag()){System.out.println("主线程可以看到改动值");}}}
}
class visibilityTest extends Thread{private boolean flag=false;@Overridepublic void run(){try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}flag=true;System.out.println("子线程将flag改为:"+flag);}public boolean isFlag(){return flag;}
}
结果主线程无法看到flag的变化:
二、解决方案
1、加锁
做法:在访问共享变量之前,为包含共享变量的类加锁;
原理:加锁后,会清空线程的工作内存,被锁保护的所有字段会从主内存中重新读取到工作内存,释放锁后,会将这个线程工作内存的共享变量全部刷新回主内存,实现线程间变量可见
示例代码:
while(true){synchronized (visibilityTest.class){if(vt.isFlag()){System.out.println("主线程可以看到改动值");}}}
结果:
2、使用volatile关键字
原理:当有线程改变了主内存中的共享变量值的时候,会立刻同步到主内存中去,其他线程线程若使用共享变量,选择直接去主内存读取,实现线程间变量可见值,不去工作内存中读取
做法:给变量前加volatile关键字
示例代码:
private volatile boolean flag=false;
结果: