课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
对虚拟机的学习与应用是每一位Java编程开发程序员都需要熟练掌握的一个编程知识,而本文我们就简单来了解一下,Java程序员需要掌握哪些虚拟机技术知识。
虚拟机在进行代码编译时,对改变顺序后不会对终结果造成影响的代码,虚拟机不一定会按我们写的代码顺序运行,有可能进行重排序。实际上虽然重排后不会对变量值有影响,但会造成线程安全问题。
重排序又可以分为三种:
编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序
指令级并行的重排序。现代CPU采用了指令级并行技术来将多条指令重叠执行。对于不存在数据依赖的指令,CPU可以改变语句对应机器指令的执行顺序
内存系统的重排序。由于CPU使用三级缓存结构,这使得数据加载和存储操作看上去可能是在乱序执行的
不过重排序也不是随便重排的,发生指令重排序的前提是:在单线程下不影响执行结果、对没有数值依赖的代码进行重排序。这就是as-if-serial语义。在多线程情况下有一套更具体的规则,那就是happens-before原则。
happens-before由以下八大原则组成:
程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作(线程的执行结果有序)
锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作
volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作
传递规则:如果操作A先行发生于操作B,操作B先行发生于操作C,则可以得出操作A先行发生于操作C
线程启动规则:Thread对象的start()方法先行发生于该线程的其他任何操作
线程中断规则:对线程中断方法interrupt()的调用先行发生于被中断线程检测到中断事件的发生
线程终结规则:线程中所有操作先行发生于线程的终止检测。通过Thread.join()方法结束、Thread.isAlive()方法的返回值等手段检测到线程已经终止执行。比如在A线程中调用B.join()方法,B线程执行完成后,B对共享变量的修改,对A来说是可见的
对象终结规则:一个对象的初始化方法完成先行发生于该对象的finalize()方法的开始
如果两个操作不满足上述八大原则中的任意一个,那么这两个操作就没有顺序保证,虚拟机可以对这两个操作进行重排序。如果操作Ahappens-before操作B,那么A在内存所做的修改对B都是可见的。
而volatile是通过插入内存屏障(MemoryBarrier),在内存屏障前后禁止重排序优化,以此实现有序性。
内存屏障有两个作用:一是保证特定操作的执行顺序,二是保证某些变量的内存可见性。
volatile内存语义的实现:JMM针对编译器制定的volatile重排序规则表
【免责声明】:本内容转载于网络,转载目的在于传递信息。文章内容为作者个人意见,本平台对文中陈述、观点保持中立,不对所包含内容的准确性、可靠性与完整性提供形式地保证。请读者仅作参考。更多内容请加danei0707学习了解。欢迎关注“达内在线”参与分销,赚更多好礼。