前言
笔者在研究 volatile 关键词的使用时,意外发现了以下四种案例情况,感觉颇为神奇,于是进行记录。限于笔者才疏学浅,无法暂时无法更进一步研究问题的本质与底层的内容,所以希望能够抛砖引玉,得来更多更优秀深入的见解。
这是笔者的github的测试项目地址:点击前往,可以查看完整的代码。
1. 第一种情况
寻常情况下,线程执行过程中突然对其变量进行变动
这是最寻常的问题,run方法 中将 active 设为 true 后,while 一直用的就是这个 true ,不会去内存中刷新这个值,也就导致了 while死循环。
线程:
1-1
测试:
1-2
2. 第二种情况
对变量使用 volatile关键字 修饰情况下,线程执行过程中突然对其变量进行变动
加上 volatile关键字 后,每次使用到 active变量 都将拿到最新的值,所以 stop方法 改 active 的值后,while 就能拿到最新的 active值 为 false ,然后结束循环。
volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
线程:
2-1
测试:
2-2
3. 第三种情况
这种情况比较特殊,在while循环中加入输入打印语句下,线程执行过程中突然对其变量进行变动
线程:
3-1
测试:
3-2
那么为什么输出语句能导致 run方法 的 while循环 发现 active 已经被修改了呢?
因为 println 里有用到了 synchronized 这个同步关键字。
如图:
3-3
而synchronized将导致
获得同步锁
清空工作内存
从主内存拷贝对象副本到工作内存
执行代码(计算或者输出等)
刷新主内存数据
释放同步锁
所以真正的起作用的不是输出语句,而是 synchronized ,把输出语句换成什么都没做的同步区块也能实现相同的效果。
如图:
3-4
但是,这又产生了另一个问题:为什么在 stop方法 里用到输出语句(也是内部的 synchronized 起作用),不会影响 while 这个方法的 active 读取呢?难道作用的只是这个方法内数据刷新,而不是整个线程?
我将stop方法中的输出语句放在active修改后,想着是否能够因为synchronized的数据刷新使得while发现active已经变了,于是停下来,然而并没有。
如图:
那么,这又是为什么呢?
因为整个运行过程存在两个线程,一个是main线程,一个volatileTestThread2线程。
两个线程都有一个active的变量的副本在它们的工作内存中(真正的active是放在主内存中)
run方法在volatileTestThread2内调用运行,所以synchronized影响的是volatileTestThread2的工作内存里变量的与主内存之间的刷新
stop方法是main线程调用的,所以synchronized是影响main线程的工作内存与主内存之间的刷新。
二者是不同的。
这也就解释了“为什么在Stop方法里用到输出语句(也是内部的synchronized起作用),不会影响while这个方法的active读取呢?”这个问题。
4. 第四种情况
在while循环中加入Sleep下,线程执行过程中突然对其变量进行变动
线程:
4-1
测试:
4-2
我们都知道,sleep将使得线程进入休眠(等待状态),操作系统调度程序不调度睡眠线程以接收CPU时间。
那么等待状态结束后,线程进入就绪状态以及被调度选中后执行的这个过程,线程是否是进行了内存变量的刷新?或者是进行了某些底层处理,导致产生了和前文synchronized使用后一样的结果?
正在研究中...