题记
在写单例模式的时候涉及到了线程安全,继而又涉及到了volatile、无序写入、synchronized等内容到此为止有必要了解下JMM了。
介绍
在Java虚拟机中通过java内存模型来 屏蔽 各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能够达到一致的内存访问效果 。
性能一致性方案
性能一致性方案(下图)
java也有有采用类似方案(下图)
方案带来的挑战:
可见性
一个线程写入的数据是否能立刻马上被其它线程看到。是否存在不能被看到的可能性?
应对-可见性
- volatile 关键字,被它修饰后表示:线程本地缓存失效,每次从主存里面拉去数据。
- 同步锁有序执行
原子性
一个操作是否可以被一个线程一个计算机写指令完成?如果存在多个写指令完成的操作就会破坏掉原子性。(高级语言的一个指令往往被分割成1个或者多个计算机指令)
应对=原子性
- atomicXX解决方案
- 基本变量(除 long,double外)的赋值操作。64位系统也被拆分位2个指令集合
- 同步锁有序执行
重排序
编译器和处理器为了优化执行效率可能会调整指令执行顺序。
方案带来的挑战
有序性
一个指令集合是否被按照一定的顺序执行?重新排序后是否与原有执行顺序一致?
应对-有序性(happens-before)
1、程序次序规则:一个线程内,按照代码顺序,书写在前面的操作先行发生于书写在后面的操作。
2、锁定规则:一个unLock操作先行发生于后面对同一个锁的Lock()操作。
3、volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作。
4、传递规则:如果操作A先行发生与操作B,而操作B先行发生于操作C,则操作A先行发生于操作C。
5、线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作。
6、线程终端规则:对线程interrupt()方法的调用先行发生与被中断线程的代码检测到中断事件的发生(只有执行了interrupt()方法才可以检测到中断事件的发生)。
7、线程终结规则:线程中所有操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束,Thread.isAlive()的返回值手段检测到线程已经终止执行。
8、对象终结规则:一个对象的初始化完成先行发生于它的finallze方法的开始。
总结
上面提到的原子性、可见性、有序性等解决方案是有关系的,其中happens-before 是其它的基础。