volatile被喻为轻量级的"synchronized",虽然一定程度上要比synchronized关键字效率要高,但它也有不足之处,就是不具有互斥性和原子性。
volatile关键字的主要作用就是保证各线程之间的可见性,意思就是在多线程环境下,某个共享变量如果被其中一个线程给修改了,其他线程能够立即知道这个共享变量已经被修改了,当其他线程要读取这个变量的时候,最终会去内存中读取,而不是从自己的工作空间中读取,我们来看一段代码。
public class TestVolatile implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
}
flag=true;
System.out.println("flag=" + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
static class Thread2{
public static void main(String[] args) {
TestVolatile t1 = new TestVolatile();
new Thread(t1).start();
while (true) {
if (t1.isFlag() == true) {
System.out.println(Thread.currentThread().getName()+"===============");
break;
}
}
}
}
}
这段代码正常的话应该输出主线程中的数据“===================”,然而运行之后并没有
原因就是main线程首先执行此时主存中的flag为false,run线程执行时把flag变成true在还没有提交到主线程时main线程又抢占到flag,此时的flag依旧为false,由于while(true)的执行效率特别高,高到方法体内的flag一直抢占不到true的时候,所以打印时就无法输出“============”。如图:
啥时候我们加一个synchronized也可以解决,但前面我们也提到了 synchronized太重量,所以此时我们可以在变量之前加一个volatile关键字使各线程之间的数据具有可见性,可理解为 run方法将flag变成true之后,主存中的flag立即变成true以便main线程能够及时看到。
private volatile boolean flag = false;