黃岡網(wǎng)站建設(shè)哪家便宜學(xué)網(wǎng)絡(luò)營銷
分析&回答
Cache Line可以簡單的理解為CPU Cache中的最小緩存單位。目前主流的CPU Cache的Cache Line大小都是64Bytes。假設(shè)我們有一個512字節(jié)的一級緩存,那么按照64B的緩存單位大小來算,這個一級緩存所能存放的緩存?zhèn)€數(shù)就是512/64 = 8個。具體參見下圖:
代碼示例:
public class CacheLine {private static class T {public volatile long x = 0L;//long類型占據(jù)8個字節(jié)}public static T[] arr = new T[2];static {arr[0] = new T();arr[1] = new T();//兩個數(shù)組緊挨著保證在內(nèi)存中也是挨在一起的}public static void main(String[] args) throws Exception{Thread t1 = new Thread(() -> {for (long i = 0; i<10000000L; i++) {arr[0].x = i;//修改一千萬次}});Thread t2 = new Thread(() -> {for (long i = 0; i<10000000L; i++) {arr[1].x = i;//修改一千萬次}});final long start = System.currentTimeMillis();t1.start();t2.start();t1.join();//讓t1線程先執(zhí)行完t2.join();//讓t2線程執(zhí)行完System.out.println(System.currentTimeMillis() - start);//join 保證主線程的這段代碼最后執(zhí)行}
}
復(fù)制代碼
執(zhí)行結(jié)果為 300ms左右
上面代碼中 arr[0] 和 arr[1]會在同一個cache line中,而每個cache line 是cpu 讀入的最基本單位,在我們使用vaolatile 之后線程t1對x的1000000萬次修改都要刷新內(nèi)存通知t2,而同樣t2對x的修改也要告訴t1。這樣就會存在頻繁的cache line 和內(nèi)存的刷新讀取。
如果我們將 對x的修飾的valitile去掉執(zhí)行結(jié)果為10ms左右\
使用緩存行對其的方式代碼示例:
public class CacheLine {private static class parent {public volatile long p1,p2,p3,p4,p5,p6,p7;//創(chuàng)建七個long 基本數(shù)據(jù)類型的成員變量占據(jù)56個字節(jié)}private static class T extends parent{public volatile long x = 0L;//long類型占據(jù)8個字節(jié)}public static T[] arr = new T[2];static {arr[0] = new T();arr[1] = new T();//兩個數(shù)組緊挨著保證在內(nèi)存中也是挨在一起的}public static void main(String[] args) throws Exception{Thread t1 = new Thread(() -> {for (long i = 0; i<10000000L; i++) {arr[0].x = i;//修改一千萬次}});Thread t2 = new Thread(() -> {for (long i = 0; i<10000000L; i++) {arr[1].x = i;//修改一千萬次}});final long start = System.currentTimeMillis();t1.start();t2.start();t1.join();//讓t1線程先執(zhí)行完t2.join();//讓t2線程執(zhí)行完System.out.println(System.currentTimeMillis() - start);//join 保證主線程的這段代碼最后執(zhí)行}
}
復(fù)制代碼
執(zhí)行結(jié)果為 100ms左右
現(xiàn)成t1一次讀入x 包括p1p2p3p4p5p6p7的所有變量64個字節(jié)剛好占據(jù)一個緩存行,線程t2 也是如此,所以他們對變量x的修改都不用刷新內(nèi)存通知對方提高了性能。
為什么這里不包括對象頭的那部分呢,因為對相頭不是使用的部分,不會讀入緩存,我們用到的只是成員變量
總結(jié)為cpu對于內(nèi)存的讀入到緩存的數(shù)據(jù)是按照緩存行的大小(64k)來讀取的。
反思&擴(kuò)展
cache 是為了進(jìn)一步提升計算機(jī)性能引入的存儲結(jié)構(gòu),cache和內(nèi)存的最小的傳輸單位是cache line,因為每個物理core有自己獨享的L1、L2 cache,并且一個cache line可能存在多個cache中,所以就出現(xiàn)了MESI協(xié)議保證cache line的一致性。 進(jìn)而又引入了cache line的偽共享的問題,為了進(jìn)一步降低cache line偽共享所帶來的的消耗,我們應(yīng)該盡量避免多個線程同時修改的不同變量在同一個cache line中。雖然真實業(yè)務(wù)場景中,cache line的消耗占比可能會被弱化很多,但是追求極致的程序猿們,又怎么能放過這樣一個無意義的消耗呢!
喵嗚面試助手:一站式解決面試問題,你可以搜索微信小程序 [喵嗚面試助手]?或關(guān)注 [喵嗚刷題] -> 面試助手?免費刷題。如有好的面試知識或技巧期待您的共享!