Java指令重排
1 | public class Main{ |
1.不加Thread.sleep(100)
程序会正常结束,大多数情况下,在启动新线程的时候,主线程后面的会获得执行。
1 | public void run() { |
通过验证发现, System.out.println(“new thread start”) 并不会输出。
2.加Thread.sleep(100)
奇怪的现象发生了。这时候,新开的线程不会结束。why?
编译的过程有
其中中间代码是和平台无关的,编译器在中间代码后面可以进行一些和平台无关的代码优化,在目标代码生成的时候,编译器当然也可以根据目标平台支持的特性进行优化,常见的指令重排可以是CPU流水线优化,IO重排等。当然JVM也会对你写的代码进行一些优化,发生在编译阶段和运行阶段都有可能。
主要还是编译器以及CPU为了优化代码或者执行的效率而执行的优化操作;应用条件是单线程场景下,对于并发多线程场景下,指令重排会产生不确定的执行效果
(原文链接https://blog.csdn.net/blueheart20/article/details/52117761[链接](https://blog.csdn.net/blueheart20/article/details/52117761))
3 如何防止指令重排?
volatile关键字可以保证变量的可见性,因为对volatile的操作都在Main Memory中,而Main Memory是被所有线程所共享的,这里的代价就是牺牲了性能,无法利用寄存器或Cache,因为它们都不是全局的,无法保证可见性,可能产生脏读。
volatile还有一个作用就是局部阻止重排序的发生,对volatile变量的操作指令都不会被重排序,因为如果重排序,又可能产生可见性问题。
在保证可见性方面,锁(包括显式锁、对象锁)以及对原子变量的读写都可以确保变量的可见性。但是实现方式略有不同,例如同步锁保证得到锁时从内存里重新读入数据刷新缓存,释放锁时将数据写回内存以保数据可见,而volatile变量干脆都是读写内存。
(原文链接:https://blog.csdn.net/blueheart20/article/details/52117761[链接](https://blog.csdn.net/blueheart20/article/details/52117761))
1 | // 在run方法里面进行跨对象访问。也会避免当前这个优化 |