下面这个程序缓存一致性问题,initflag第二个线程更改为true后,第一个线程while循环中如果没有输出那个代码或者加个同步块就跳不出循环。对于synchronized不应该是针对同一个监视器对象的话会保持内存可见吗? 再者initflag没有在同步代码块中包含,而是在while条件中,为什么线程1能够将自己的工作内存副本清除去主内存获取到线程2更改后的值呢?(不用volatile关键字)
package myTest;
public class ThreadMesiTest {
public static boolean initFlag = false;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
while(!initFlag){
System.out.println("进来了");
}
System.out.println("获取到了新值跳出循环了");
}
});
thread1.start();
Thread.sleep(5000);
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
initFlag = true;
System.out.println("更新啦falg的值");
}
});
thread2.start();
}
}
这个问题前几天回答过 可惜没被采纳
原因是因为
线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中
线程获取锁时,JMM会把该线程对应的本地内存置为无效,从主内存中读取共享变量
所以注意:
System.out.println("进来了"); 中
其实是有加synchronized锁的,所以子线程进入synchronized的时候会强制从主内存中读取共享变量,
当读取到true时,就跳出
线程 thread1 是先执行的,肯定能进入 while 循环打印“进来了” 。
5 秒后 thread2 修改了 initFlag 后,下一轮的 thread1 while 循环就结束了。
不知道你是怎么在 if 中添加同步块的,但是如果要加应该是这样的:
public void run() {
while (true) {
synchronized (ThreadMesiTest.class) {
if(initFlag) {
break;
}
}
System.out.println("进来了");
}
System.out.println("获取到了新值跳出循环了");
}
“为什么线程1能够将自己的工作内存副本清除去主内存获取到线程2更改后的值呢”应该不是这样的,线程1 读取变量时应该是从共享内存中获取的。
你是想问为什么没有锁或者volatile或者关键字,共享变量也能在主内存和工作内存中体现出及时的更新吧?
并不是说工作内存在没有同步处理的情况下就一定不会更新了,一般只有在短时间内高并发的情况才会出现不能及时刷新的情况,因为CPU在执行过程中会自行刷新缓存。
你可以多启动几个线程验证,或者在原来的程序上记录下时间戳。
当你的修改了initFlag了之后会有1毫秒(有时候甚至不到1毫秒的延迟)。