java内存模型
所有的变量都存储在主内存(Main Memory)中。每个线程还有自己的工作内存(Working Memory),线程的工作内存中保存了该线程使用到的变量的主内存的副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程之间值的传递都需要通过主内存来完成。
可见性:可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果。
使用volatile修饰的变量在修改后可以被立即刷新到主内存中,其他线程可以立即看到修改后的值.当有其他线程需要读取时,它会去主内存中读取最新值。相反,普通的共享变量被修改之后,不能保证及时更新到主内存,导致某些线程读取时还是旧值,因此无法保证其可见性。
看代码:
class VolatileDemo extends Thread{
public boolean flag = true;
public void setFlag(boolean flag){
this.flag = flag;
}
@Override
public void run() {
System.out.println("子线程开始.....");
while (flag){
}
System.out.println("子线程执行结束....");
}
}
public class ThreadVolatileDemo {
public static void main(String[] args) throws InterruptedException {
VolatileDemo volatileDemo = new VolatileDemo();
volatileDemo.start();
Thread.sleep(1000);
volatileDemo.setFlag(false);
System.out.println("flag已经修改为false!");
Thread.sleep(1000);
System.out.println("flag==="+volatileDemo.flag);
}
}
运行结果如下,当变量没被volatile修饰时,主线程修改共享变量的值后并没有更新到主内存中,所以另一个线程无法读取到修改后的值导致出现死循环。
使用volatile修饰变量:
运行结果,程序可以正常结束,
但是,如果在while循环体中加上一段输出语句,也能够停止线程,原因在哪里,看下源码
public void run() {
System.out.println("子线程开始.....");
while (flag){
System.out.println("子线程正在执行循环任务!!");
}
System.out.println("子线程执行结束....");
}
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
原来是因为,输出语句的内容,有一个同步代码块,进入、离开同步代码块,都会和主内存的共享变量的值保证一致,从而实现了可见性。