JMM:Java Memory Model(Java内存模型),围绕着在并发过程中如何处理可见性、原子性、有序性这三个特性而建立的模型。
可见性:JMM提供了volatile变量定义、final、synchronized块来保证可见性。
例如:线程a在将共享变量x=1写入主内存的时候,如何保证线程b读取共享变量x的值为1,这就是JMM做的事情。JMM通过控制主内存与每个线程的本地内存之间的交互,来为java程序员提供内存可见性保证。
原子性:JMM提供保证了访问基本数据类型的原子性(其实在写一个工作内存变量到主内存是分主要两步:store、write),但是实际业务处理场景往往是需要更大的范围的原子性保证,所以模型也提供了synchronized块来保证
有序性:这个概念是相对而言的,如果在本线程内,所有的操作都是有序的,如果在一个线程观察另一个线程,所有的操作都是无序的,前句是“线程内表现为串行行为”,后句是“指令的重排序”和“工作内存和主内存同步延迟”现象,模型提供了volatile和synchronized来保证线程之间操作的有序性。
重排序:在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序(编译器、处理器),就是因为这些重排序,所以可能会导致多线程程序出现内存可见性问题(数据安全问题)和有序性问题。
JMM是如何处理的呢?
对于编译器,JMM的编译器重排序规则会禁止特定类型的编译器重排序
对于处理器重排序,JMM的处理器重排序规则会要求java编译器在生成指令序列时,插入特定类型的内存屏障(memory barriers,intel称之为memory fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序
总之一句话,JMM是通过禁止特定类型的编译器重排序和处理器重排序来为程序员提供一致的内存可见性保证。
A线程具体什么时候刷新共享数据到主内存是不确定的,假设我们使用了同步原语(synchronized,volatile和final),那么刷新的时间是确定的,例如:线程A释放锁后会同步到主内存,线程B获取锁后会同步主内存数据
即“A线程释放锁--B线程获取锁”可以实现A,B线程之间的通信