Java编程语言允许线程访问的共享变量,为了确保共享变量能够被准确和一致性的更新,线程应该确保通过排他锁单独获取到某个变量。
如果一个字段被声明成了volatile,那么他在Java线程的内存模型里面就可以被所有线程看到这边变量的一致性。
被volatile修饰的变量后,把下列代码通过汇编编译时发现多了lock前缀命令
insatcen = new Insatcen() // insatcen 被 volatile 修饰 复制代码
那么这个lock前缀命令在多核处理器下会引发两个事情。
那么这个是什么意思呢?那就要简单说一下Java的内存模型了
在Java中 所有的实例域、静态域和数组元素都存在堆内存中,堆内存在线程之间是共享的。而局部变量、方法定义参数和异常处理器是线程私有的,不会和其他线程共享。它们不存在内存可见行问题。
Java线程之间的通信是由Java内存模型控制的(JMM)。 如图所示:
从抽象的角度看,线程之间共享变量储存在主内存中。但是每个线程由都有自己私有的本地内存,里面存放了该线程读/写共享变量的副本。但是这个本地内存是JMM的一个抽象概念,不是真实存在的。
所有如果线程A去更新一个共享变量X,线程A先更新自己的本地缓存,当线程A和线程B通信的时候,才把X更新到主内存中,并且线程B重新从主内存中获取。并且整个过程都必须要通过JMM来控制,这就保证了内存的可见行。
那么编译器中的lock命令就是引发来线程A和线程B的通信。来引发数据写会公共区域,并让其他线程的内存地址无效
在执行程序的时候,为了提高性能。编译器和处理器常常需要对指令进行重新排序。
排序主要分为一下三类:
所有从源码到最终的结果 可能回经过这三种重排序:
源代码 > 编译器优化的重排序 > 指令级别的重排序 > 内存系统的重排序>最终的顺序
而这些重新排序都会导致多线程程序出现内存可见行的问题。JMM编译器会禁止特定类型的编译器重排序。通过插入特定的内存屏障指令,来禁止特定类型的处理器重新排序。 其他更多的重排序知识可以参考 《Java并发编程的艺术》 这本书