溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java并發(fā)編程的知識點有哪些

發(fā)布時間:2021-11-30 15:02:48 來源:億速云 閱讀:141 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要介紹“Java并發(fā)編程的知識點有哪些”,在日常操作中,相信很多人在Java并發(fā)編程的知識點有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java并發(fā)編程的知識點有哪些”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

    殺死一個開發(fā),只需要變更三次需求。

2.1-volatile的應用(wall la tai l 還是 wall lei tai l)

它在多處理器開發(fā)中保證了共享變量的“可見性”??梢娦缘囊馑际钱斠粋€線程

修改一個共享變量時,另外一個線程能讀到這個修改的值,它不會引起線程上下文的切換和調(diào)度

Java并發(fā)編程的知識點有哪些

CPU術語定義

volatile是如何來保證可見性的呢?讓我們在X86處理器下通過工具獲取JIT編譯器生成的

匯編指令來查看對volatile進行寫操作時,CPU會做什么事情。

Java代碼如下。

instance = new Singleton();      // instance是volatile變量

轉(zhuǎn)變成匯編代碼,如下。

0x01a3de1d: movb $0×0,0×1104800(%esi);0x01a3de24: lock addl $0×0,(%esp);

Lock前綴的指令在多核處理器下會引發(fā)了兩件事情[1]。

1)將當前處理器緩存行的數(shù)據(jù)寫回到系統(tǒng)內(nèi)存。

2)這個寫回內(nèi)存的操作會使在其他CPU里緩存了該內(nèi)存地址的數(shù)據(jù)無效。

2.volatile的使用優(yōu)化

著名的Java并發(fā)編程大師Doug lea在JDK 7的并發(fā)包里新增一個隊列集合類Linked-

TransferQueue,它在使用volatile變量時,用一種追加字節(jié)的方式來優(yōu)化隊列出隊和入隊的性

能。LinkedTransferQueue的代碼如下。

/** 隊列中的頭部節(jié)點 */private transient f?inal PaddedAtomicReference<QNode> head;/** 隊列中的尾部節(jié)點 */private transient f?inal PaddedAtomicReference<QNode> tail;static f?inal class PaddedAtomicReference <T> extends AtomicReference T> {// 使用很多4個字節(jié)的引用追加到64個字節(jié)     Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe;     PaddedAtomicReference(T r) {super(r);     }}public class AtomicReference <V> implements java.io.Serializable {private volatile V value;// 省略其他代碼}

追加字節(jié)能優(yōu)化性能?這種方式看起來很神奇,但如果深入理解處理器架構就能理解其中的奧秘。讓我們先來看看LinkedTransferQueue這個類,它使用一個內(nèi)部類類型來定義隊列的頭節(jié)點(head)和尾節(jié)點(tail),而這個內(nèi)部類PaddedAtomicReference相對于父類AtomicReference只做了一件事情,就是將共享變量追加到64字節(jié)。我們可以來計算下,一個對象的引用占4個字節(jié),它追加了15個變量(共占60個字節(jié)),再加上父類的value變量,一共64個

字節(jié)。

為什么追加64字節(jié)能夠提高并發(fā)編程的效率呢?因為對于英特爾酷睿i7、酷睿、Atom和NetBurst,以及Core Solo和Pentium M處理器的L1、L2或L3緩存的高速緩存行是64個字節(jié)寬,不支持部分填充緩存行,這意味著,如果隊列的頭節(jié)點和尾節(jié)點都不足64字節(jié)的話,處理器會將它們都讀到同一個高速緩存行中,在多處理器下每個處理器都會緩存同樣的頭、尾節(jié)點,當一個處理器試圖修改頭節(jié)點時,會將整個緩存行鎖定,那么在緩存一致性機制的作用下,會導致其他處理器不能訪問自己高速緩存中的尾節(jié)點,而隊列的入隊和出隊操作則需要不停修改頭節(jié)點和尾節(jié)點,所以在多處理器的情況下將會嚴重影響到隊列的入隊和出隊效率。Doug lea使用追加到64字節(jié)的方式來填滿高速緩沖區(qū)的緩存行,避免頭節(jié)點和尾節(jié)點加載到同一個緩存行,使頭、尾節(jié)點在修改時不會互相鎖定。

那么是不是在使用volatile變量時都應該追加到64字節(jié)呢?不是的。在兩種場景下不應該

使用這種方式。

·緩存行非64字節(jié)寬的處理器。如P6系列和奔騰處理器,它們的L1和L2高速緩存行是32個字節(jié)寬。

·共享變量不會被頻繁地寫。因為使用追加字節(jié)的方式需要處理器讀取更多的字節(jié)到高速緩沖區(qū),這本身就會帶來一定的性能消耗,如果共享變量不被頻繁寫的話,鎖的幾率也非常小,就沒必要通過追加字節(jié)的方式來避免相互鎖定。

不過這種追加字節(jié)的方式在Java 7下可能不生效,因為Java 7變得更加智慧,它會淘汰或重新排列無用字段,需要使用其他追加字節(jié)的方式。

2.2.1Java對象頭

synchronized用的鎖是存在Java對象頭里的。如果對象是數(shù)組類型,則虛擬機用3個字寬(Word)存儲對象頭,如果對象是非數(shù)組類型,則用2字寬存儲對象頭。在32位虛擬機中,1字寬等于4字節(jié),即32bit

Java對象頭里的Mark Word里默認存儲對象的HashCode、分代年齡和鎖標記位

Java并發(fā)編程的知識點有哪些

2.2.2 鎖的升級與對比

Java SE 1.6中,鎖一共有4種狀態(tài),級別從低到高依次是:無鎖狀態(tài)、偏向鎖狀態(tài)、輕量級鎖狀

態(tài)和重量級鎖狀態(tài)

鎖可以升級,但不可降級

1.偏向鎖(Biased Locking)

個人理解:偏向,偏心,如果在運行過程中,遇到了其他線程搶占鎖,則持有偏向鎖的線程會被掛起,此時會設置偏向鎖的標識

在大多數(shù)情況下,鎖總是由同一線程多次獲得,不存在多線程競爭,所以出現(xiàn)了偏向鎖。其目標就是在只有一個線程執(zhí)行同步代碼塊時能夠提高性能。

鎖的撤銷以及鎖的關閉都是會產(chǎn)生開銷的

偏向鎖的適用場景

始終只有一個線程在執(zhí)行同步塊,在它沒有執(zhí)行完釋放鎖之前,沒有其它線程去執(zhí)行同步塊,在鎖無競爭的情況下使用,一旦有了競爭就升級為輕量級鎖,升級為輕量級鎖的時候需要撤銷偏向鎖,撤銷偏向鎖的時候會導致stop the word操作;

Java并發(fā)編程的知識點有哪些

2.輕量級鎖

偏向鎖運行在一個線程進入同步塊的情況下,當?shù)诙€線程加入鎖爭用的時候,偏向鎖就會升級為輕量級鎖; 

(1)輕量級鎖加鎖

線程在執(zhí)行同步塊之前,JVM會先在當前線程的棧楨中創(chuàng)建用于存儲鎖記錄的空間,并

將對象頭中的Mark Word復制到鎖記錄中,官方稱為Displaced Mark Word。然后線程嘗試使用

CAS將對象頭中的Mark Word替換為指向鎖記錄的指針。如果成功,當前線程獲得鎖,如果失

敗,表示其他線程競爭鎖,當前線程便嘗試使用自旋來獲取鎖。

(2)輕量級鎖解鎖

輕量級解鎖時,會使用原子的CAS操作將Displaced Mark Word替換回到對象頭,如果成

功,則表示沒有競爭發(fā)生。如果失敗,表示當前鎖存在競爭,鎖就會膨脹成重量級鎖

Java并發(fā)編程的知識點有哪些

鎖的優(yōu)缺點的對比

Java并發(fā)編程的知識點有哪些

重量級鎖Synchronized

特別記錄一下

當作用于靜態(tài)方法時,鎖住的是Class實例,又因為Class的相關數(shù)據(jù)存儲在永久帶PermGen(jdk1.8則是metaspace),永久帶是全局共享的,因此靜態(tài)方法鎖相當于類的一個全局鎖,會鎖所有調(diào)用該方法的線程;

從JVM規(guī)范中可以看到Synchonized在JVM里的實現(xiàn)原理,JVM基于進入和退出Monitor對象來實現(xiàn)方法同步和代碼塊同步,但兩者的實現(xiàn)細節(jié)不一樣。代碼塊同步是使用monitorenter和monitorexit指令實現(xiàn)的,而方法同步是使用另外一種方式實現(xiàn)的

總結

Java并發(fā)編程的知識點有哪些

以下摘抄博客

https://blog.csdn.net/xiaobaixiongxiong/article/details/100933396

在所有的鎖都啟用的情況下線程進入臨界區(qū)時會先去獲取偏向鎖,如果已經(jīng)存在偏向鎖了,則會嘗試獲取輕量級鎖,如果以上兩種都失敗,則啟用自旋鎖,如果自旋也沒有獲取到鎖,則使用重量級鎖,沒有獲取到鎖的線程阻塞掛起,直到持有鎖的線程執(zhí)行完同步塊喚醒他們;

偏向鎖是在無鎖爭用的情況下使用的,也就是同步開在當前線程沒有執(zhí)行完之前,沒有其它線程會執(zhí)行該同步塊,一旦有了第二個線程的爭用,偏向鎖就會升級為輕量級鎖,一點有兩個以上線程爭用,就會升級為重量級鎖;

如果線程爭用激烈,那么應該禁用偏向鎖。

鎖優(yōu)化

以上介紹的鎖不是我們代碼中能夠控制的,但是借鑒上面的思想,我們可以優(yōu)化我們自己線程的加鎖操作;

減少鎖的時間

不需要同步執(zhí)行的代碼,能不放在同步快里面執(zhí)行就不要放在同步快內(nèi),可以讓鎖盡快釋放;

減少鎖的粒度

它的思想是將物理上的一個鎖,拆成邏輯上的多個鎖,增加并行度,從而降低鎖競爭。它的思想也是用空間來換時間;

---------摘抄完畢

Java并發(fā)編程的知識點有哪些

自旋鎖 VS 適應性自旋鎖

阻塞或喚醒一個Java線程需要操作系統(tǒng)切換CPU狀態(tài)來完成,這種狀態(tài)轉(zhuǎn)換需要耗費處理器時間。如果同步代碼塊中的內(nèi)容過于簡單,狀態(tài)轉(zhuǎn)換消耗的時間有可能比用戶代碼執(zhí)行的時間還要長。

在許多場景中,同步資源的鎖定時間很短,為了這一小段時間去切換線程,線程掛起和恢復現(xiàn)場的花費可能會讓系統(tǒng)得不償失。如果物理機器有多個處理器,能夠讓兩個或以上的線程同時并行執(zhí)行,我們就可以讓后面那個請求鎖的線程不放棄CPU的執(zhí)行時間,看看持有鎖的線程是否很快就會釋放鎖。

而為了讓當前線程“稍等一下”,我們需讓當前線程進行自旋,如果在自旋完成后前面鎖定同步資源的線程已經(jīng)釋放了鎖,那么當前線程就可以不必阻塞而是直接獲取同步資源,從而避免切換線程的開銷。這就是自旋鎖。

Java并發(fā)編程的知識點有哪些

自旋鎖本身是有缺點的,它不能代替阻塞。自旋等待雖然避免了線程切換的開銷,但它要占用處理器時間。如果鎖被占用的時間很短,自旋等待的效果就會非常好。反之,如果鎖被占用的時間很長,那么自旋的線程只會白浪費處理器資源。所以,自旋等待的時間必須要有一定的限度,如果自旋超過了限定次數(shù)(默認是10次,可以使用-XX:PreBlockSpin來更改)沒有成功獲得鎖,就應當掛起線程。

自旋鎖的實現(xiàn)原理同樣也是CAS,AtomicInteger中調(diào)用unsafe進行自增操作的源碼中的do-while循環(huán)就是一個自旋操作,如果修改數(shù)值失敗則通過循環(huán)來執(zhí)行自旋,直至修改成功。

Java并發(fā)編程的知識點有哪些

自旋鎖在JDK1.4.2中引入,使用-XX:+UseSpinning來開啟。JDK 6中變?yōu)槟J開啟,并且引入了自適應的自旋鎖(適應性自旋鎖)。

自適應意味著自旋的時間(次數(shù))不再固定,而是由前一次在同一個鎖上的自旋時間及鎖的擁有者的狀態(tài)來決定。如果在同一個鎖對象上,自旋等待剛剛成功獲得過鎖,并且持有鎖的線程正在運行中,那么虛擬機就會認為這次自旋也是很有可能再次成功,進而它將允許自旋等待持續(xù)相對更長的時間。如果對于某個鎖,自旋很少成功獲得過,那在以后嘗試獲取這個鎖時將可能省略掉自旋過程,直接阻塞線程,避免浪費處理器資源。

在自旋鎖中 另有三種常見的鎖形式:TicketLock、CLHlock和MCSlock,本文中僅做名詞介紹,不做深入講解,感興趣的同學可以自行查閱相關資料。

---以上來源于美團技術博客

請解釋偏向鎖對 synchronized 與 ReentrantLock 的價值?

偏向鎖?

對synchronize有用

Java偏向鎖(Biased Locking)是Java6引入的一項多線程優(yōu)化。 

偏向鎖,顧名思義,它會偏向于第一個訪問鎖的線程,如果在運行過程中,同步鎖只有一個線程訪問,不存在多線程爭用的情況,則線程是不需要觸發(fā)同步的,這種情況下,就會給線程加一個偏向鎖。 

如果在運行過程中,遇到了其他線程搶占鎖,則持有偏向鎖的線程會被掛起,JVM會消除它身上的偏向鎖,將鎖恢復到標準的輕量級鎖。

它通過消除資源無競爭情況下的同步原語,進一步提高了程序的運行性能。

ReentrantLock已經(jīng)實現(xiàn)了偏向鎖

synchronized實際也是可重入的只不過是jvm層次的

到此,關于“Java并發(fā)編程的知識點有哪些”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續(xù)學習更多相關知識,請繼續(xù)關注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI