public static boolean flag =false;
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(()->{
int i = 0;
while (!flag){
i++;
}
System.out.println(i);
});
thread.start();
Thread.sleep(1000);
flag = true;
}
不会停止运行,也没有打印出i的值。
深度优化,编译器会对程序进行优化。
while (!flag){ i++; }
——> if(!flag){while(true){i++}
改变了flag的值,也不会停止while循环。
在while循环中加上print语句或者sleep能够停止,活性失败。print中包含IO操作和synchronized,锁的释放会将线程工作内存中写的操作同步到主内存中。如果在while循环中添加锁操作(有释放锁的操作),下次循环会去读取最新的flag值。IO操作同样可以(具体原因不清楚)。sleep操作,猜想是时间片的切换,重新竞争CPU资源导致的缓存行失效。
volatile关键字。保证可见性,一定的有序性,不保证原子性。
硬件层面。CPU高速缓存,总线锁,缓存锁(缓存一致性协议)
MSI、MESI、MOSI
MESI:Modify(修改)、Exclusive(独占)、Shared(共享)、Invalid(失效)
优化MESI,引入store buffer,异步对缓存行中数据的写操作,通知其他CPU缓存行失效后才执行写操作。会导致有序性问题,指令重排序。
内存屏障,同步到主内存,防止指令重排序。
-
Happens-Before模型
-
程序顺序规则(as-if-serial语义)
- 不能改变程序的执行结果(在单线程环境下,执行结果不变)
- 依赖问题,如果两个指令存在依赖关系,是不允许重排序的
- 传递性规则
- volatile变量规则
- 监视器锁规则
-
start规则
- 线程启动前的数据对于启动的线程是可见的
-
Join规则
- 线程调用join()执行完之后的数据对于join()之后的数据访问是可见的