it.learn.other

记录自己学习的点滴

Java并发编程的艺术 第三章 Java内存模型 3.1 Java内存模型的基础 JMM通过控制主内存与每个线程的本地内存之间的交互,来为Java程序员提供内存可见性保证。

JMM对正确同步的多线程程序的内存一致性做了如下保证

如果程序是正确同步的,程序的执行将具有顺序一致性---即程序的执行结果与该程序在顺序一致性内存模型中的执行结果相同。这对于程序员来说是一个极强的保证。这里的同步是指广义上的同步,包括对常用同步原语(synchronized、volatile和final)的正确使用。

3.5 锁的内存语义 3.5.4 concurrent包的实现 Java的CAS会使用现代处理器上提供的高效机器级别的原子指令,这些原子指令以原子方式对内存执行读-改-写操作,这是在多处理器中实现同步的关键(从本质上来说,能够支持原子性读-改-写指令的计算机,是顺序计算图灵机的异步等价机器,因此任何现代的多处理器都会去支持某种能对内存执行原子性读-改-写操作的原子指令)。同时,volatile变量的读/写和CAS可以实现线程之间的通信。把这些特性整合在一起,就形成了整个concurrent包得以实现的基石。 image

3.7 happens-before happens-before是JMM最核心的概念,理解happens-before是理解JMM的关键。

从JMM设计者的角度,需要考虑两个关键因素:
. 程序员对内存模型的使用。程序员希望内存模型易于理解、易于编程。程序员希望基于一个强内存模型来编写代码。
. 编译器和处理器对内存模型的实现。编译器和处理器希望内存模型对它们的束缚越少越好,这样它们就可以做尽可能多的优化来提高性能。编译器和处理器希望实现一个弱内存模型。

JMM把happens-before要求禁止的重排序分为下面两类
. 会改变程序执行结果的重排序
. 不会改变程序执行结果的重排序

JMM对这两种不同性质的重排序,采取了不同的策略,如下:
. 对于会改变程序执行结果的重排序,JMM要求编译器和处理器必须禁止这种重排序。
. 对于不会改变程序执行结果的重排序,JMM对编译器和处理器不做要求(JMM允许这种重排序)。

在java语言规范中,要求所有线程在执行java程序时必须要遵守intra-thread semantics, intra-thread semantics允许那些在单线程内,不会改变单线程程序执行结果的重排序。

3.8.4 基于类初始化的解决方案 JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在执行类的初始化阶段,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。 对于类或接口的初始化,Java语言规范制定了精巧而复杂的类初始化处理过程,分为下面5个阶段:

第1阶段:通过在Class对象上同步(即获取Class对象的初始化锁),来控制类或接口的初始化。这个获取锁的线程会一直等待,直到当前线程能够获取到这个初始化锁。

第2阶段:线程A执行类的初始化,同时线程B在初始化锁对应的condition上等待。

第3阶段:线程A设置state=initialized,然后唤醒在condition中等待的所有线程。

第4阶段:线程B结束类的初始化阶段。

第5阶段:线程C执行类的初始化的处理。

第4章 Java并发编程基础