日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

synchronized 关键字原理

發(fā)布時(shí)間:2025/3/21 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 synchronized 关键字原理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

眾所周知?synchronized?關(guān)鍵字是解決并發(fā)問題常用解決方案,有以下三種使用方式:

  • 同步普通方法,鎖的是當(dāng)前對(duì)象。
  • 同步靜態(tài)方法,鎖的是當(dāng)前?Class?對(duì)象。
  • 同步塊,鎖的是?()?中的對(duì)象。

實(shí)現(xiàn)原理:?JVM?是通過進(jìn)入、退出對(duì)象監(jiān)視器(?Monitor?)來實(shí)現(xiàn)對(duì)方法、同步塊的同步的。

具體實(shí)現(xiàn)是在編譯之后在同步方法調(diào)用前加入一個(gè)?monitor.enter?指令,在退出方法和異常處插入?monitor.exit?的指令。

其本質(zhì)就是對(duì)一個(gè)對(duì)象監(jiān)視器(?Monitor?)進(jìn)行獲取,而這個(gè)獲取過程具有排他性從而達(dá)到了同一時(shí)刻只能一個(gè)線程訪問的目的。

而對(duì)于沒有獲取到鎖的線程將會(huì)阻塞到方法入口處,直到獲取鎖的線程?monitor.exit?之后才能嘗試?yán)^續(xù)獲取鎖。

流程圖如下:

通過一段代碼來演示:

public static void main(String[] args) {synchronized (Synchronize.class){System.out.println("Synchronize");}}

使用?javap -c Synchronize?可以查看編譯之后的具體信息。

public class com.crossoverjie.synchronize.Synchronize {public com.crossoverjie.synchronize.Synchronize();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnpublic static void main(java.lang.String[]);Code:0: ldc #2 // class com/crossoverjie/synchronize/Synchronize2: dup3: astore_1**4: monitorenter**5: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;8: ldc #4 // String Synchronize10: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V13: aload_1**14: monitorexit**15: goto 2318: astore_219: aload_120: monitorexit21: aload_222: athrow23: returnException table:from to target type5 15 18 any18 21 18 any }

可以看到在同步塊的入口和出口分別有?monitorenter,monitorexit?指令。

鎖優(yōu)化

synchronized?很多都稱之為重量鎖,JDK1.6?中對(duì)?synchronized?進(jìn)行了各種優(yōu)化,為了能減少獲取和釋放鎖帶來的消耗引入了偏向鎖和輕量鎖。

輕量鎖

當(dāng)代碼進(jìn)入同步塊時(shí),如果同步對(duì)象為無鎖狀態(tài)時(shí),當(dāng)前線程會(huì)在棧幀中創(chuàng)建一個(gè)鎖記錄(Lock Record)區(qū)域,同時(shí)將鎖對(duì)象的對(duì)象頭中?Mark Word?拷貝到鎖記錄中,再嘗試使用?CAS?將?Mark Word?更新為指向鎖記錄的指針。

如果更新成功,當(dāng)前線程就獲得了鎖。

如果更新失敗,?JVM?會(huì)先檢查鎖對(duì)象的?Mark Word?是否指向當(dāng)前線程的鎖記錄。

如果是則說明當(dāng)前線程擁有鎖對(duì)象的鎖,可以直接進(jìn)入同步塊。

不是則說明有其他線程搶占了鎖,如果存在多個(gè)線程同時(shí)競(jìng)爭(zhēng)一把鎖,輕量鎖就會(huì)膨脹為重量鎖

解鎖

輕量鎖的解鎖過程也是利用?CAS?來實(shí)現(xiàn)的,會(huì)嘗試鎖記錄替換回鎖對(duì)象的?Mark Word?。如果替換成功則說明整個(gè)同步操作完成,失敗則說明有其他線程嘗試獲取鎖,這時(shí)就會(huì)喚醒被掛起的線程(此時(shí)已經(jīng)膨脹為重量鎖)

輕量鎖能提升性能的原因是:

認(rèn)為大多數(shù)鎖在整個(gè)同步周期都不存在競(jìng)爭(zhēng),所以使用?CAS?比使用互斥開銷更少。但如果鎖競(jìng)爭(zhēng)激烈,輕量鎖就不但有互斥的開銷,還有?CAS?的開銷,甚至比重量鎖更慢。

偏向鎖

為了進(jìn)一步的降低獲取鎖的代價(jià),JDK1.6?之后還引入了偏向鎖。

偏向鎖的特征是:鎖不存在多線程競(jìng)爭(zhēng),并且應(yīng)由一個(gè)線程多次獲得鎖。

當(dāng)線程訪問同步塊時(shí),會(huì)使用?CAS?將線程 ID 更新到鎖對(duì)象的?Mark Word?中,如果更新成功則獲得偏向鎖,并且之后每次進(jìn)入這個(gè)對(duì)象鎖相關(guān)的同步塊時(shí)都不需要再次獲取鎖了。

釋放鎖

當(dāng)有另外一個(gè)線程獲取這個(gè)鎖時(shí),持有偏向鎖的線程就會(huì)釋放鎖,釋放時(shí)會(huì)等待全局安全點(diǎn)(這一時(shí)刻沒有字節(jié)碼運(yùn)行),接著會(huì)暫停擁有偏向鎖的線程,根據(jù)鎖對(duì)象目前是否被鎖來判定將對(duì)象頭中的?Mark Word?設(shè)置為無鎖或者是輕量鎖狀態(tài)。

偏向鎖可以提高帶有同步卻沒有競(jìng)爭(zhēng)的程序性能,但如果程序中大多數(shù)鎖都存在競(jìng)爭(zhēng)時(shí),那偏向鎖就起不到太大作用。可以使用?-XX:-userBiasedLocking=false?來關(guān)閉偏向鎖,并默認(rèn)進(jìn)入輕量鎖。

其他優(yōu)化

適應(yīng)性自旋

在使用?CAS?時(shí),如果操作失敗,CAS?會(huì)自旋再次嘗試。由于自旋是需要消耗?CPU?資源的,所以如果長(zhǎng)期自旋就白白浪費(fèi)了?CPU。JDK1.6加入了適應(yīng)性自旋:

如果某個(gè)鎖自旋很少成功獲得,那么下一次就會(huì)減少自旋。

總結(jié)

以上是生活随笔為你收集整理的synchronized 关键字原理的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。