Java内存模型
一、Java内存模型的基础
1.1并发编程模型的两个关键问题:
两个关键问题,线程之间如何通信和如何同步。两种方式,共享内存和消息传递。Java里线程的通信是通过共享内存,线程的同步是显示进行的,而通信则是隐式进行的。
1.2Java内存模型的抽象结构:
实际上就是说Java线程之间的通信是通过共享内存来进行交互。
1.3从源代码到指令序列的重排序:
重排序,让指令序列重新排序而更高效地运行程序。Java中根据不同的处理器会禁用对应的重排序规则(内存屏障),从而保证了内存可见性。
1.4并发编程模型的分类:
对于处理器来说主要需要重排序的操作是:写-读操作,否则可能会导致数据的脏读。不同的处理器分别在“读-读”、“写-写”、“读-写”、“写-读”操作上可能都有可能进行重排序。而在不需要重排序的处理器上,Java提供了内存屏障指令来避免没有必要的重排序。
1.5happens-before概念:
操作A happens-before 操作B,那么操作A的结果就对操作B可见,happens-before概念并不意味着操作A就一定发生在操作B之前。
二、重排序
对指令的重排序是对程序执行的一种优化;
2.1数据依赖性
如果两个操作操作同一数据,只要有个操作是“写”,那么这两个操作之间存在数据依赖性;
2.2as-if-serial语义
不管怎么重排序,单线程的处理结果不能被改变;
2.3重排序对多线程的影响
两个线程分别操作两个数据,线程A的两个数据没有数据依赖性,而线程B的两个数据存在数据依赖性,那么线程A中可能发生的重排序可能会影响到线程B的操作的结果。
三、顺序一致性
顺序一致性模型是一个理想化的内存模型;
3.1数据竞争与顺序一致性
数据竞争:两个线程之间,线程A在写一个数据,线程B又在读这个数据,并且两个线程没有做同步;而在JMM中,做了同步操作的结果可以保证和顺序一致性模型的结果保持一致;
3.2顺序一致性内存模型
顺序一致性的两大特性:
(1)一个线程的所有操作必须按照程序的顺序执行;
(2)不管是否同步,所有线程只能看到单一的操作执行顺序;
3.3同步程序的顺序一致性效果
同步的程序之间,临界区内的代码可能会进行重排序,但是最终的结果和顺序一致性模型是一样的,这样就既保证了顺序一致性的效果,又能对性能进行优化;
3.4未同步程序的执行特性
四、volatile的内存语义