当一个 Java 程序员工作一段时间之后,不可避免的要去了解 JVM,而了解 JVM 的时候,自然就会看到 Java 的内存模型,但是个人看过有太多的人概念不清不楚,有太多的人把 Java 内存结构,记得曾经看过一篇文章,一个同学去面试,面试官问他:简单聊聊 Java 的内存模型,他说完之后,面试官说:你说的不对啊,内存模型应该是堆、栈、常量池、方法区、程序计数器等等,然后他瞬间就不想去这家公司了,这不是让一个半吊子去当面试官吗,自己概念都没搞清楚就去说别人,个人也看过太多文章把这个搞错,所以今天就写了一篇小文章,说说自己对 JMM 的理解,当然我说的可能也不对,也不可能说透。
1. 主内存和工作内存
Java 内存模型规定了所有的变量都存储在主内存,每个线程还有自己的工作内存,线程的工作内存中存储了被该线程使用到的变量的主内存存储拷贝,程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,不能直接读写主内存中的变量,不同的线程之间也无法直接访问对方工作内存的变量,线程间变量值的传递均需要通过主内存来完成,主内存和工作内存之间的交互有 8 个人原子性的操作来实现,具体详细的可以再查资料。
2. 重排序
重排序是编译器和处理器为了优化程序性能,而对指令顺序进行重新排序的一种手段。但 as-if-serial 语义的意思是:不管怎么重排序,单线程程序的执行结果都不能被改变,所以编译器和处理器都不会对存在数据依赖关系的操作做重排序。
3. happens-before
如果操作 1 happens-before 操作 2,那么第操作1的执行结果将对操作 2 可见,而且操作1的执行顺序排在第操作 2 之前。两个操作之间存在 happens-before 关系,并不意味着一定要按照 happens-before 原则制定的顺序来执行。如果重排序之后的执行结果与按照 happens-before 关系来执行的结果一致,那么这种重排序并不非法。另外 happens-before 具有传递性,由于这些规则的存在,Java 内存模型会保证重排序后的执行,在线程内看起来和串行的效果是一样的,这就是程序的顺序一致性。
4. 对于 volatile 型变量的特殊规则
当一个变量被定义为 volatile 之后,他将具备两种特性,1. 保证此变量对所有线程的可见行,这里的可见行是指当一个线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的,而普通变量做不到这一点。但是这个要多说一点,有些同学看到这可能认为:volatile 变量在各个线程中是一致的,所以基于 volatile 变量的运算在并发下是安全的,其实这句话的论据对,但结论是错的,因为 Java 中的运算并非原子的,volatile 的应用场景在于读多写少的地方:例如修饰一个 boolean 变量作为一个开关。2. 禁止指令重拍优化,这个在写单例的时候,我想大家都已经知道了,不再赘述。
5. final
被 final 修饰的字段,一旦完成了初始化,其他线程就能看到它,并且它也不会再变了。即只要不可变对象被正确的构建出来(没有发生 this 引用溢出),它就是线程安全的。
全文完,如果本文对您有所帮助,请花 1 秒钟帮忙点击一下广告,谢谢。
作 者: BridgeLi,https://www.bridgeli.cn
原文链接: https://www.bridgeli.cn/archives/645
版权声明:非特殊声明均为本站原创作品,转载时请注明作者和原文链接。