如果我们要想深入了解Java并发编程,就要先理解好Java内存模型。Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。原始的Java内存模型效率并不是很理想,因此Java1.5版本对其进行了重构,现在的Java8仍沿用了Java1.5的版本。
在java中每个线程都有一块本地内存,而本地内存存放的变量是主内存的副本。相当于在线程启动时候线程会复制主内存的变量到自己的本地内存。当本地内存变量改变时候就同步到主内存。如果有多个变量线程共享变量,这时候主内存又会刷新同步所有线程的变量。而这种同步并不是实时的。
如何和证明每个线程内部都有一份主内存副本?
下面有段代码
package com.mylienkd;
public class MyThread implements Runnable {
private Integer nubmer=0;
@Override
public void run() {
while(true){
if(nubmer>1){
System.out.println(Thread.currentThread()+"子线程循环结束");
break;
}
}
}
public void setNubmer(Integer nubmer) {
this.nubmer = nubmer;
}
public static void main(String[] args) throws Exception {
MyThread thread=new MyThread();
new Thread(thread).start();
//睡眠1s
Thread.sleep(1000);
thread.setNubmer(10);
//睡眠3s
Thread.sleep(3000);
System.out.println("主线程结束");
}
}
在此运行此代码得到如下结果
仔细观察代码以及结果可以发现,在主线程更改变量nubmer为10后,主线程执行结束,但是控制台并没退出一直在执行。
这是因为子线程并没有退出循环。因为子线程本地内存的number为0,主内存中的值并没有刷新到子线程中的本内存的所以才会出现这种状态。
如何解决此方法。java为了避免这种情况提供了关键字volatile ,在number变量上加上volatile关键字
private volatile Integer nubmer=0;
运行此代码得到结果
可以看到此代码在主线程退出前,子线程就先退出了循环。这是因为volatile关键字实时更新此变量。在number变量更改时,就同步刷新更改其他线程的副本变量。
在很多地方叫做volatile关键字解决可见性。