java并发 cpu高_java高并发核心要点|系列5|CPU内存伪共享
上節(jié)提到的:偽共享,今天我們來(lái)說(shuō)說(shuō)。
那什么是偽共享呢?
這得從CPU的緩存結(jié)構(gòu)說(shuō)起。以下如圖,CPU一般來(lái)說(shuō)是有三級(jí)緩存,1 級(jí),2級(jí),3級(jí),越上面的,越靠近CPU的,速度越快,成本也越高。也就是說(shuō)速度方面:1級(jí)>2級(jí)>3級(jí)。
圖1
圖2
如上圖2我們來(lái)看看不同級(jí)別的緩存的時(shí)延:
到CPU的延遲CPU時(shí)鐘耗時(shí)
主內(nèi)存
很多(Multiple)
~60-80 ns
L3 緩存
~40-45 周期
~15 ns
L2 緩存
~10 周期
~3 ns
L1 緩存
~3-4 周期
~1 ns
寄存器
一周期
小于1ns,飛快
更多CPU架構(gòu)信息:https://blog.csdn.net/karamos/article/details/80126704
說(shuō)到這里,我們要理解一個(gè)很重要的概念:緩存行。什么是緩存行?
首先我們來(lái)看這幾級(jí)緩存,其中,1,2級(jí)緩存是CPU核心私有的,也就是說(shuō)每個(gè)核,之間不會(huì)共享1,2級(jí)緩存,那它們之間怎么通信或共享數(shù)據(jù)呢?
答案是:3級(jí)緩存,如下圖:
那core1,和core2之間,是通過(guò)什么方式共享緩存呢?
答案是:緩存行!
什么是緩存行?簡(jiǎn)單來(lái)說(shuō),就是CPU內(nèi)核之間共享數(shù)據(jù)的最小單位。如下圖:x,y是在同一個(gè)緩存行,那每次CPU內(nèi)核之間通信時(shí)交換x,y值,可以同時(shí)共享兩個(gè)值。是不是很高效?
是的,一般情況下,如果x,y是屬于數(shù)組內(nèi)的數(shù)據(jù) ,是可以達(dá)到高效共享數(shù)據(jù)的功能,但問(wèn)題又來(lái)了:如果,x,y并不屬于同一數(shù)組,x屬于core1,而y屬于core2,這個(gè)時(shí)候,如果core1更新了x,會(huì)導(dǎo)致y值失效了。為什么失效了,因?yàn)樗麄冊(cè)谕痪彺嫘小_@時(shí),只有把緩存行 flush到主存后, 其他內(nèi)核中的相應(yīng)的緩存行才會(huì)被置為過(guò)期數(shù)據(jù),而緩存行什么時(shí)候flush到memory, 這個(gè)是有一定延時(shí)的 ,在這個(gè)延時(shí)當(dāng)中, 其他CPU core是無(wú)法得知你的更新的 。那么內(nèi)核core2再去讀取Y的值時(shí),由于L1的緩存里的數(shù)據(jù)已失效,那么就需要從L3獲取,然后放入L2,再放入L1。 這樣核心2讀取Y值就需要從L3級(jí)的緩存讀了。但是明明是內(nèi)核core1修改的X的值,卻影響到內(nèi)核2去讀取Y值了。同理,如果是內(nèi)核2去修改Y的值,也會(huì)影響內(nèi)核1去讀取X的值。
簡(jiǎn)單來(lái)說(shuō),x,y同放在緩存行,而且它們又屬于不同CPU內(nèi)核的數(shù)據(jù)值(事實(shí)上CPU內(nèi)核也就是代碼中的:線程)。那就會(huì)因?yàn)楦髯愿缕渲幸粋€(gè)值,而導(dǎo)致緩存失效。
這就是著名的偽共享問(wèn)題。
有沒(méi)有什么解決方案呢?
有的。
方案是:緩存行填充。
還是回到上面的例子,如果x,y同放到同一個(gè)緩存行,會(huì)造成偽共享。很簡(jiǎn)單,那就不要放在一起好了!
比如:x有8byte(字節(jié)),而一般緩存行總共有64byte。那其他剩下的位置,我們就用預(yù)定的空變量填充就行了,代碼如下 (java6版本):
public final static classVolatileLong {
public volatile long x= 0L;
public long p1, p2, p3, p4, p5, p6,p7;//緩存行填充}
這個(gè)時(shí)候,core1更新x值,也就不會(huì)影響y值,從而造成偽共享問(wèn)題。
上面的代碼是java6的解決方案。
JAVA 8下的方案
在JAVA 8中,緩存行填充終于被JAVA原生支持了。JAVA 8中添加了一個(gè)@Contended的注解,添加這個(gè)的注解,將會(huì)在自動(dòng)進(jìn)行緩存行填充,如下代碼:
import sun.misc.Contended;
@Contended
public class VolatileLong {
public volatile long value = 0L;
}
執(zhí)行時(shí),必須加上虛擬機(jī)參數(shù)-XX:-RestrictContended,@Contended注釋才會(huì)生效。很多文章把這個(gè)漏掉了,那樣的話實(shí)際上就沒(méi)有起作用。
這就是偽共享的解決方案,多么簡(jiǎn)單!
本系列完畢!
如果各位讀者,還有什么意見(jiàn)或建議,歡迎拍磚吐槽!
總結(jié)
以上是生活随笔為你收集整理的java并发 cpu高_java高并发核心要点|系列5|CPU内存伪共享的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: mysql blgg__MySQL_ex
- 下一篇: 高性能计算机存储部件有磁盘阵列,信息存储