1.可见性
static class demoThread implements Runnable{
private boolean flag=false;
@Override
public void run() {
// TODO Auto-generated method stub
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
flag=true;
System.out.println("flag:"+flag);
}
public boolean getFlag() {
return flag;
}
}
public static void main(String args[]) {
demoThread dt=new demoThread();
Thread t=new Thread(dt);
t.start();
while(true) {
if(dt.getFlag()) {
System.out.println("over ...");
break;
}
}
}
执行结果
flag:true
首先jvm会给每个线程分配一个独立的内存,dt线程改变flag的值后只同步给了主存,flag的值被改变以后主线程中的while循环并没有停下来,因为while循环执行速度过快,只是从主线程自己的内存中去读取flag的值,而没有去主存中读取flag的值,修改代码如下:
private volatile boolean flag=false;
执行结果
flag:true
over ...
加上volatile关键字后flag的值改变会通知说有需要读取flag变量的操作去主存读取flag最新的值,解决了可见性问题
2.重排序
static int x,y;
static int m,n;//测试用的信号变量
public static void main(String[] args) throws InterruptedException {
int count = 10000000;
for(int i=0;i<count;++i){
x=y=m=n=0;
//线程一
Thread one = new Thread(){
public void run() {
m=1;
x=n;
};
};
//线程二
Thread two = new Thread(){
public void run() {
n=1;
y=m;
};
};
//启动并等待线程执行结束
one.start();
two.start();
one.join();
two.join();
//输出结果
if(x==0&&y==0)
System.out.println("index:"+i+" {x:"+x+",y:"+y+"}");
}
}
jvm会在不影响单个线程执行结果的情况下对指令执行的顺序进行重新排序,以上这段代码的四个操作的顺序可能是以下几种情况:
m=1 x=n n=1 y=m 结果 x=0 y=1
m=1 n=1 x=n y=m 结果 x=1 y=1
n=1 y=m m=1 x=m 结果 x=1 y=0
x=n y=m n=1 m=1 结果 x=0 y=0
对被volatile修饰的变量的操作一定优先之后的操作,以此可以阻止重排序现象
修改代码
static volatile int m,n;
之后程序便不会出现x=0 y=0的这种情况