JAVA内存模型:JMM & volatile关键字
通过阅读一些资料,简单分享下自己对java运行时线程、运行内存、主内存之间的关系已经volatile关键字是如何保证内存中线程间的可见性的
JMM内存模型
下图简要展示了java内存模型之间的关系
线程1、线程2、线程3中分别有各自的工作内存与执行引擎,运行时,工作内存会从主内存先去读取变量值并在工作内存中拷贝一份该变量的副本,之后执行引擎执行代码时直接去读取工作内存中的变量副本进行运算等操作。
从这张图中可以看出,线程间的运算、变量值都是相对隔离的,如果代码处理不当,并发时就会有同一个变量在不同线程间同时操作造成数据有误。
为了便于理解,用以下代码举例:
private static int a = 1;
public static void main(String[] args) {
new Thread(() -> {
a = 5;
}).start();
}
下图是线程中的工作内存从主内存中读取数据并在执行引擎中进行计算的过程:
下图是执行引擎执行后赋值给主内存的过程:
read(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
load(载入):作用于工作内存的变量,它把 read 操作从主内存中得到的变量值放入工作内存的变量副本中。
use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。
assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。1
volatile关键字
用最简单最笼统的语言描述volatile关键字就是:保证线程间变量的内存可见性。
那么具体是如何保证同一变量在不同线程间的可见性的呢?就要用到我们上述提到JMM来进行说明
不用volatile关键字时的代码举例
private static boolean isCycle = false;
public static void main(String[] args) throws Exception {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("----------start cycle thread----------");
while (!isCycle) {
}
System.out.println("----------end cycle thread----------");
}
}).start();
//保证上面的线程一定进入循环
Thread.sleep(1000);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("modify isCycle start");
isCycle = true;
System.out.println("modify isCycle end");
}
}).start();
}
代码的输出结果为
从结果中可以知道,前一个线程中的循环没有跳出来,所以没有打印end日志,这是为什么呢,我们依然拿JMM的图来说明。
(未完待续)