多线程学习(三)- CPU缓存模型与java内核模型

CPU 缓存模型
在计算机中,所有的运算操作都是由cpu的寄存器来操作完成的,cpu指令在执行这些操作的时候往往涉及了数据的读写操作。cpu所能访问的数据只能是计算机的主存(RAM)。随着现代工业的发展CPU 的计算速度提升了,而受制于制造工艺以及成本的限制计算机的内存没有得到有效的提升。从而导致计算的cpu和内存性能差距越来显著,两者的速度严重的不对等,按传统的FSB的方式导致cpu资源受到极大限制,从而降低了cpu的整体吞吐量。
由此背景下就有cpu缓存模型,通过在cpu和内存之间直接新增缓存设计,目前的缓存数量增加到三级,靠近cpu的缓存为L1,依次为L2,L3。
在这里插入图片描述
L1:保存了从L2高速缓存中读取的缓存行。
L2:保存了从L3高速缓存中读取的缓存行。
L3:保存了从MAIN MEMEORY中读取的缓存行。

此时多线程访问内存数据流程大致为:
在这里插入图片描述
java内核模型(java memory model)
由于缓存的出现,提高了CPU的吞吐能力,但是也引入了缓存不一致的问题。在多处理器系统中,每个处理器都有自己的的高速缓存,而它们又共享同一主内存,当多个处理器的运算任务都设计到同一块内存区域时,将可能导致各自的缓存数据不一致,这个时候就需要通过缓存一致性协议来保证数据的正确性,不同的操作系统使用缓存一致性协议都各不相同。
因为各种硬件和操作系统的内存访问是有差异的,Java为了程序能在各种平台下运行达到一致的内存访问效果,于是定义了Java内存模型(Java Memory Mode,JMM)来对特定内存或高速缓存的读写访问过程进行抽象。
JMM与JVM的区别:
JVM是指Java内存结构描述的是JVM对内存的逻辑划分。
而JMM实际上是一种规范。它描述了Java程序的运行行为,包括多线程操作对共享内存读取时,所能读取到的值应该遵守的规则。
JMM的作用:
绝大多数时间都会把对象信息保存在内存中。但是在此期间,编译器、处理器或者缓存都可能会把变量从分配的内存中取出处理再放回。比如我们在while循环中判断flag变量是否为true来执行一段特定的逻辑,那么编译器为了优化可能会选择把flag值取到缓存中。此时主存中的flag值可能会被其它线程所改变,但是此线程是无法感知的,从而没有获得最新数值。直到某个特定的时机触发此线程从主存中刷新flag值。所有这些优化都是为了程序有更好的性能。在单线程的程序中,这种优化对于用户来讲是毫无感知的,不过多线程的程序中,这种优化有些时候会造成难以预料的结果。
JMM允许编译器和缓存保持对数据操作顺序优化的自由度。除非程序使用Synchronized或者volatile显式的告诉处理器需要确保可见性。这意味着如果你没有进行同步,那么多线程程序对于数据的操作,将会呈现不同的顺序。也就是前面一节讲的有序性,我们基于代码顺序对数据赋值顺序的推论,在多线程程序中可能会不成立。
Happens-Before规则:
Happens-Before是指JMM为程序的所有操作定义了一套规则,这个规则被称为Happens-Before,无论两个操作是否属于同一个线程,如果想要操作A立刻知道操作B的结果,则这两个操作要满足Happens-Before规则。如果在多线程中,存在多个线程共同操作一个共享变量,而他们又不符合Happpens-Before规则,就会导致程序处于混乱状态。除非使用同步的方式使得程序以串行化方式从而符合Happens-Before规则。
Happens-Before定义的一些规则

  1. 程序顺序规则。如果程序中A操作在B操作之前,那么线程中A操作将在B操作前执行。
  2. 锁原则。不同线程对同一个锁的lock操作一定在unclock前。
  3. volatile变量原则。对于volatile变量的写操作会早于对其的读操作。
  4. 线程启动原则。A线程中调用threadB.start()方法,那么threadB.start()方法会早于B线程中中的任何动作执行。
  5. 传递规则。如果A早于B执行,B早于C执行,那么A一定早于C执行。
  6. 线程中断规则:线程interrupt()方法的一定早于检测到线程的中断信号。
  7. 线程终结规则:如果线程A终结了,并且导致另外一个线程B中的ThreadA.join()方法取得返回,那么线程A中所有的操作都早于线程B在ThreadA.join()之后的动作发生。
  8. 对象终结规则:一个对象初始化操作肯定先于它的finalize()方法。

volatile实现原理
1 、volatile 的有序性则是通过内存屏障。所谓的内存屏障就是在屏障前的所有指令可以重排序的,屏障之后的指令也可以重排序,但是重排序的时候不能越过内存屏障。也就是说内存屏障前的指令不会被重排序到内存屏障之后,反之亦然。
2、缓存一致性协议保证可见性(volatile修饰变量写操作会刷到主存并且独占这篇内存区域,值被更新后任何读取此变量的线程都会被通知需要更新副本)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值