記得關(guān)注我【看點(diǎn)代碼再上班】片林,訂閱更多好文!
大家好费封,我是tin,這是我的第7篇原創(chuàng)文章全文共計(jì)2163字18圖怀骤,預(yù)計(jì)閱讀時(shí)間13分鐘
圖拍攝于深圳桃園南山圖書館蒋伦,年前某個(gè)陽光明媚的周六弓摘,看到掛滿的燈籠,覺得甚是喜慶痕届。文章較長(zhǎng)韧献,先上一個(gè)目錄:上個(gè)全文目錄:
二研叫、CPU緩存架構(gòu)
三锤窑、CPU緩存行
四、偽共享
五嚷炉、結(jié)語
一渊啰、Doug lea
在微博上看到這么一句話,挺有意思的申屹。
Doug Lea是誰绘证?為什么這么說?估計(jì)還真挺多人不認(rèn)識(shí)他吧哗讥。
Doug Lea迈窟,中文名為道格·利。java.util.concurrent并發(fā)包的作者忌栅。說他是這個(gè)世界上對(duì)Java影響力最大的一個(gè)人,一點(diǎn)也不為過。因?yàn)閮纱蜫ava歷史上的大變革索绪,他都間接或直接的扮演了舉足輕重的角色湖员。2004年所推出的Tiger。Tiger廣納了15項(xiàng)JSRs的語法及標(biāo)準(zhǔn)瑞驱,其中一項(xiàng)便是JSR-166娘摔。JSR-166是來自于Doug編寫的util.concurrent包,主要是關(guān)于J.U.C的技術(shù)規(guī)范唤反。
上文摘抄自百度百科:
JSRs(Java Specification Requests)凳寺,表示Java規(guī)范請(qǐng)求,由JCP成員向委員會(huì)提交的Java發(fā)展議案彤侍,經(jīng)過一系列流程后肠缨,如果通過最終會(huì)體現(xiàn)在未來的Java中。
JCP全稱Java Community Process 盏阶,翻譯中文即是:Java社區(qū)進(jìn)程晒奕。JCP成立于1998年,官網(wǎng)地址https://www.jcp.org名斟,由社會(huì)各界Java組成的社區(qū)脑慧,主要規(guī)劃和領(lǐng)導(dǎo)Java的發(fā)展。
二砰盐、CPU緩存架構(gòu)
國內(nèi)另一位大神闷袒,dubbo的創(chuàng)作者,曾經(jīng)在他的ppt寫過這樣的一頁
或許有人已經(jīng)猜到這ppt作者是誰的岩梳,有興趣可自行了解(需要完整ppt也可聯(lián)系我D抑琛)。ppt描述的背后原理就是偽共享問題蒋腮。
說起偽共享淘捡,還得從cpu的緩存架構(gòu)說起。
CPU緩存可以分為一級(jí)緩存池摧,二級(jí)緩存焦除,三級(jí)緩存,每一級(jí)緩存中所儲(chǔ)存的全部數(shù)據(jù)都是下一級(jí)緩存的一部分作彤。當(dāng)CPU要讀取一個(gè)數(shù)據(jù)時(shí)膘魄,首先從一級(jí)緩存中查找,如果沒有找到再從二級(jí)緩存中查找竭讳,如果還是沒有就從三級(jí)緩存或內(nèi)存中查找创葡。一般來說,每級(jí)緩存的命中率大概都在80%左右绢慢,也就是說全部數(shù)據(jù)量的80%都可以在一級(jí)緩存中找到灿渴,只剩下20%的總數(shù)據(jù)量才需要從二級(jí)緩存洛波、三級(jí)緩存或內(nèi)存中讀取。
越靠近 CPU 的緩存越快也越小骚露。所以 L1 緩存很小但很快蹬挤,緊接著L2 大一些,也會(huì)慢一些棘幸,L3更慢焰扳,最后到主存,主存保存著程序運(yùn)行的所有數(shù)據(jù)误续,由所有 CPU 核共享吨悍。
三、CPU緩存行
CPU緩存由緩存行組成蹋嵌,緩存行長(zhǎng)度為64字節(jié)育瓜,可以這么認(rèn)為,緩存行是緩存更新的基本單位欣尼。緩存每次更新都從主內(nèi)存中加載連續(xù)的 64 個(gè)字節(jié)爆雹。試想,如果在內(nèi)存中有兩個(gè)緊鄰的long型變量a和b愕鼓,當(dāng)a加載到緩存時(shí)钙态,b也可以一起被加載到緩存,下一次如果訪問b則可以直接從緩存讀取菇晃,這對(duì)讀取的效率提升是非常大的册倒。
但是,正因?yàn)榫彺娑家跃彺嫘袨榛締挝惶幚砘撬停绻鹀pu core1修改a變量驻子,core1上包含a變量的緩存行將失效,同時(shí)其他core上包含a變量的緩存行也將失效估灿。此時(shí)崇呵,如果core2要訪問和a在同一緩存行上的b變量,會(huì)被告知緩存行失效馅袁,這時(shí)只能到主內(nèi)存重新加載b變量域慷。
在《Java并發(fā)編程的藝術(shù)》一書中,第二章第11頁如是說:
Doug lea在jdk7的并發(fā)包里面新增一個(gè)隊(duì)列集合類LinkedTransferQueue汗销,它在使用volatie變量時(shí)犹褒,用一種追加字節(jié)的方式來優(yōu)化隊(duì)列出隊(duì)和入隊(duì)的性能。
四弛针、偽共享
緩存以緩存行為基本單位叠骑,當(dāng)線程修改互相獨(dú)立的變量時(shí),如果這些變量在同一緩存行中削茁,那么就會(huì)互相變量緩存值得有效性宙枷,從而影響訪問性能掉房,這就是偽共享。
看一個(gè)單元測(cè)試源碼:
package com.tin.example.falls.sharing;
import org.springframework.util.StopWatch;
/**
* title: AutoIncrement
* <p>
* description: 多線程環(huán)境下慰丛,long變量自增
*
* @author tin @看點(diǎn)代碼再上班 on 2021/2/17 下午1:28
*/
public class AutoIncrement {
public static void main(String[] args) throws InterruptedException {
StopWatch stopWatch = new StopWatch("@看點(diǎn)代碼再上班");
stopWatch.start();
System.out.println("====== start to iterate ======");
autoIncrement(new LongNumber());
stopWatch.stop();
System.out.println("cost " + stopWatch.getTotalTimeMillis() + "ms");
}
private static void autoIncrement(LongNumber longNumber) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100000000; i++) {
longNumber.n1++;
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 100000000; i++) {
longNumber.n2++;
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
static class LongNumber {
// @sun.misc.Contended
volatile long n1;
volatile long n2;
}
}
當(dāng)我啟用兩個(gè)線程圃阳,分別自增1億次n1和n2時(shí),耗時(shí)大約3000+ms
當(dāng)我在n1字段加上注解@sun.misc.Contended璧帝,重新跑程序,耗時(shí)變?yōu)?00+ms
@sun.misc.Contended注解在Java 8后新增富寿,其用來進(jìn)行緩存行填充睬隶。它可以用于類級(jí)別的修飾,同時(shí)也可以用于字段級(jí)別的修飾页徐,當(dāng)應(yīng)用于字段級(jí)別時(shí)苏潜,被注釋的字段將和其他字段隔離開來,會(huì)被加載在獨(dú)立的緩存行上变勇。
@sun.misc.Contended注解和上文ppt中提及的追加字節(jié)效果是等同的(注解要生效需在啟動(dòng)參數(shù)上加-XX:-RestrictContended)恤左。除了加注解,如果在n1和n2中間增加16個(gè)對(duì)象引用也同樣起到作用(一個(gè)對(duì)象引用4個(gè)字節(jié))搀绣。
我們要看一個(gè)對(duì)象所占的字節(jié)數(shù)大小怎么看飞袋?分享一個(gè)好東西,引用下面的包依賴:
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
代碼中顯式打印對(duì)象即可:
ClassLayout.parseInstance(obj).toPrintable()
可以看到打印出來的結(jié)果:
五链患、結(jié)語
我是tin巧鸭,一個(gè)在努力讓自己變得更優(yōu)秀的普通攻城獅。自己閱歷有限麻捻、學(xué)識(shí)淺薄纲仍,如有發(fā)現(xiàn)文章不妥之處,非常歡迎加我提出贸毕,我一定細(xì)心推敲加以修改郑叠。
看到這里請(qǐng)安排個(gè)點(diǎn)贊再走吧,堅(jiān)持原創(chuàng)不容易明棍,你的正反饋是我堅(jiān)持輸出的最強(qiáng)大動(dòng)力乡革,謝謝啦!
別忘了關(guān)注我哦署拟!???