一、java内存屏障
1.1 what?1.2 why?1.3 硬件层的内存屏障1.4 内存屏障的主要类型 二.、java内存屏障的使用
2.1 java内存屏障使用介绍2.2 volatile实现原理
2.2.1 Volatile基本介绍2.2.2 volatile作用2.2.3 volatile与synchronized对比
一、java内存屏障 1.1 what?内存屏障是一个CPU指令。
① 确保一些特定 *** 作执行的顺序
② 影响一些数据的可见性
编译器和CPU可以保证输出结果一样的情况下对指令重排序,使性能得到优化。
例:插入一个内存屏障,则相当于告诉CPU和编译器,先于这个命令的先执行,后于这个命令的必须后执行。
强制更新一次不同CPU的缓存。
1.2 why?例:一个写屏障会把这个屏障前写入的数据刷新到缓存,这样任何试图读取该数据的线程将得到最新之,而不用考虑道理是哪个cpu核心或者哪个cpu执行的。
在cpu多核场景下,为了充分利用CPU,会通过流水线将指令并行进行。为了能并行,又需要将指令进行重排序,但是指令不是在所有场景下都能进行重排序,除了本身一些规则,我们还需要保证多CPU的告诉缓存中的数据与内存报纸一致性,不能确保内存与CPU缓存数据一致性的指令也不能重排。
1.3 硬件层的内存屏障内存屏障正式通过阻止屏障两边的指令重排序来避免编译器和硬件的不正确优化而提出的一种解决办法。
① lfence:Load Barrier读屏障
② sfence : Store Barrier写屏障
③ mfence : 全能型屏障,具有ifence 和 sfence能力
④ Lock前缀,Lock不是一种内存屏障,但它能完成类似内存屏障功能。Lock会对CPU总线和高速缓存加锁
对Load Barrier来说,在读指令前插入读屏障,可以让高速缓存中的数据失效,重新从主内存加载数据
对Store Barrier来说,在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存
①LoadLoad屏障
序列Load1,Loadload,Load2
确保Load1所要读入的数据能够在被Load2和后续的load指令访问前读入。通常能执行预加载指令或/和支持乱序处理的处理器中需要显式声明Loadload屏障,因为在这些处理器中正在等待的加载指令能够绕过正在等待存储的指令。 而对于总是能保证处理顺序的处理器上,设置该屏障相当于无 *** 作。
②StoreStore 屏障
序列:Store1,StoreStore,Store2
确保Store1的数据在Store2以及后续Store指令 *** 作相关数据之前对其它处理器可见(例如向主存刷新数据)。通常情况下,如果处理器不能保证从写缓冲或/和缓存向其它处理器和主存中按顺序刷新数据,那么它需要使用StoreStore屏障。
③LoadStore 屏障
序列: Load1; LoadStore; Store2
确保Load1的数据在Store2和后续Store指令被刷新之前读取。在等待Store指令可以越过loads指令的乱序处理器上需要使用LoadStore屏障。
二.、java内存屏障的使用 2.1 java内存屏障使用介绍④StoreLoad 屏障
序列: Store1; StoreLoad; Load2
确保Store1的数据在被Load2和后续的Load指令读取之前对其他处理器可见。StoreLoad屏障可以防止一个后续的load指令 不正确的使用了Store1的数据,而不是另一个处理器在相同内存位置写入一个新数据。正因为如此,所以在下面所讨论的处理器为了在屏障前读取同样内存位置存过的数据,必须使用一个StoreLoad屏障将存储指令和后续的加载指令分开。Storeload屏障在几乎所有的现代多处理器中都需要使用,但通常它的开销也是最昂贵的。它们昂贵的部分原因是它们必须关闭通常的略过缓存直接从写缓冲区读取数据的机制。这可能通过让一个缓冲区进行充分刷新(flush),以及其他延迟的方式来实现。
①a. 通过 Synchronized关键字包住的代码区域,当线程进入到该区域读取变量信息时,保证读到的是最新的值.这是因为在同步区内对变量的写入 *** 作,在离开同步区时就将当前线程内的数据刷新到内存中,而对数据的读取也不能从缓存读取,只能从内存中读取,保证了数据的读有效性.这就是插入了StoreStore屏障
②b. 使用了volatile修饰变量,则对变量的写 *** 作,会插入StoreLoad屏障.
2.2 volatile实现原理 2.2.1 Volatile基本介绍③c. 其余的 *** 作,则需要通过Unsafe这个类来执行.
UNSAFE.putOrderedObject类似这样的方法,会插入StoreStore内存屏障
Unsafe.putVolatiObject 则是插入了StoreLoad屏障
Java语言规范第三版中对volatile的定义如下: java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致的更新,线程应该确保通过排他锁单独获得这个变量。
2.2.2 volatile作用Java语言提供了volatile,在某些情况下比锁更加方便。如果一个字段被声明成volatile,java线程内存模型确保所有线程看到这个变量的值是一致的。
2.2.3 volatile与synchronized对比能保证可见性和防止指令重排序
volatile变量修饰符如果使用恰当的话,它比synchronized的使用和执行成本会更低,因为它不会引起线程上下文的切换和调度
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)