解决线程间变量不可见性的方案
一、 背景
所有的实例变量和类变量都存储在主内存,但每个线程都有自己的工作内存,保留了主内存的共享变量的副本,线程修改的是共享变量,但是每个线程每次只能读取工作内存里的值,所以会导致变量不可见
示例代码:
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;
@Override
public 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;
结果: