1. 内存模型JMM
Java内存模型是Java虚拟机(JVM)规范中定义的一组规则,用于屏蔽各种硬件和操作系统的内存访问差异,保证多线程情况下程序的正确执行。Java内存模型规定了线程之间如何交互以及线程和内存之间的关系。它主要解决的问题是可见性、原子性和有序性。
可见性(Visibility):可见性指当一个线程修改了共享变量的值,其他线程能够立即看到这个修改。如果一个线程对共享变量的修改对其他线程不可见,可能导致数据的不一致性和错误的结果。
原子性(Atomicity):原子性是指一个操作是不可中断的,要么全部执行成功,要么全部不执行。在多线程环境下,如果某个操作是非原子性的,可能会导致数据错误或者竞态条件。
有序性(Ordering):有序性是指程序执行的顺序与代码的顺序一致。在多线程环境下,由于指令重排和线程间的交互,可能导致指令执行顺序与代码的书写顺序不一致,从而导致错误的结果。
1. 1 主内存和工作内存
在Java内存模型中,主内存(Main Memory)是所有线程共享的内存区域,而每个线程都有自己的工作内存(Working Memory)。线程的工作内存保存了该线程使用的变量的主拷贝副本。
线程在执行过程中,会把需要用到的变量从主内存复制到自己的工作内存中进行操作,然后再将修改后的值刷新回主内存。这种方式可以减少对主内存的访问,提高性能。但是也可能导致可见性问题,即一个线程对共享变量的修改对其他线程不可见。
然后可能遇到的问题如下:
所以JMM中的可见性就是当一个线程修改了某一个共享变量的值,其他线程能够立即看到这个修改。
1.2 重排序
重排序(Reordering)是计算机编程和优化中的一个概念,指的是改变程序中指令执行的顺序,以提高性能或者满足特定的优化需求。重排序在现代计算机系统中是一种常见的优化手段,但同时也可能引发一些潜在的问题。
在编程语言中,由于存在数据依赖性和内存模型的约束,编译器和处理器在执行指令时有一定的自由度来调整指令的执行顺序。这些优化不会改变程序的语义,即程序的行为应该和没有重排序时一致,但可能会影响到程序的可见行为。
重排序主要分为三种类型:
编译器重排序(Compiler Reordering):编译器在生成目标代码时可能会根据目标架构的特点进行指令重排,以提高代码的执行效率。编译器重排序通常只在不影响程序语义的情况下进行。
处理器重排序(Processor Reordering):现代处理器具有乱序执行的特性,它们可以根据指令之间的数据依赖关系和资源冲突情况,动态调整指令的执行顺序。处理器重排序可以在一定程度上提高指令的执行效率和并行性。
内存重排序(Memory Reordering):现代计算机系统中存在多级缓存和乱序执行等特性,这可能导致对内存的读写操作在不同处理器上出现重排序现象。内存重排序可能会导致可见性问题,即一个线程对共享变量的修改对其他线程不可见。
所以JMM中有序性特性就是针对重排序的。