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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

synchronized 中的 4 个优化,你知道几个?

發布時間:2025/3/11 编程问答 15 豆豆
生活随笔 收集整理的這篇文章主要介紹了 synchronized 中的 4 个优化,你知道几个? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者 | 王磊

來源 | Java中文社群(ID:javacn666)

轉載請聯系授權(微信ID:GG_Stone)

synchronized 在 JDK 1.5 時性能是比較低的,然而在后續的版本中經過各種優化迭代,它的性能也得到了前所未有的提升,上一篇中我們談到了鎖膨脹對 synchronized 性能的提升,然而它也只是“眾多” synchronized 性能優化方案中的一種,那么我們本文就來盤點一下 synchronized 的核心優化方案。

synchronized 核心優化方案主要包含以下 4 個:

  • 鎖膨脹

  • 鎖消除

  • 鎖粗化

  • 自適應自旋鎖

  • 1.鎖膨脹

    我們先來回顧一下鎖膨脹對 synchronized 性能的影響,所謂的鎖膨脹是指 synchronized 從無鎖升級到偏向鎖,再到輕量級鎖,最后到重量級鎖的過程,它叫做鎖膨脹也叫做鎖升級。JDK 1.6 之前,synchronized 是重量級鎖,也就是說 synchronized 在釋放和獲取鎖時都會從用戶態轉換成內核態,而轉換的效率是比較低的。但有了鎖膨脹機制之后,synchronized 的狀態就多了無鎖、偏向鎖以及輕量級鎖了,這時候在進行并發操作時,大部分的場景都不需要用戶態到內核態的轉換了,這樣就大幅的提升了 synchronized 的性能。

    PS:至于為什么不需要用戶態到內核態的轉換?請移步到鎖膨脹的那篇文章:《synchronized 優化手段之鎖膨脹機制》。

    2.鎖消除

    很多人都了解 synchronized 中鎖膨脹的機制,但對接下來的 3 項優化卻知之甚少,這樣會在面試中錯失良機,那么我們本文就把這 3 項優化單獨拎出來講一下吧。

    鎖消除指的是在某些情況下,JVM 虛擬機如果檢測不到某段代碼被共享和競爭的可能性,就會將這段代碼所屬的同步鎖消除掉,從而到底提高程序性能的目的。

    鎖消除的依據是逃逸分析的數據支持,如 StringBuffer 的 append() 方法,或 Vector 的 add() 方法,在很多情況下是可以進行鎖消除的,比如以下這段代碼:

    public String method() {StringBuffer sb = new StringBuffer();for (int i = 0; i < 10; i++) {sb.append("i:" + i);}return sb.toString(); }

    以上代碼經過編譯之后的字節碼如下:

    從上述結果可以看出,之前我們寫的線程安全的加鎖的 StringBuffer 對象,在生成字節碼之后就被替換成了不加鎖不安全的 StringBuilder 對象了,原因是 StringBuffer 的變量屬于一個局部變量,并且不會從該方法中逃逸出去,所以此時我們就可以使用鎖消除(不加鎖)來加速程序的運行。

    3.鎖粗化

    鎖粗化是指,將多個連續的加鎖、解鎖操作連接在一起,擴展成一個范圍更大的鎖

    我只聽說鎖“細化”可以提高程序的執行效率,也就是將鎖的范圍盡可能縮小,這樣在鎖競爭時,等待獲取鎖的線程才能更早的獲取鎖,從而提高程序的運行效率,但鎖粗化是如何提高性能的呢?

    沒錯,鎖細化的觀點在大多數情況下都是成立了,但是一系列連續加鎖和解鎖的操作,也會導致不必要的性能開銷,從而影響程序的執行效率,比如這段代碼:

    public String method() {StringBuilder sb = new StringBuilder();for (int i = 0; i < 10; i++) {// 偽代碼:加鎖操作sb.append("i:" + i);// 偽代碼:解鎖操作}return sb.toString(); }

    這里我們不考慮編譯器優化的情況,如果在 for 循環中定義鎖,那么鎖的范圍很小,但每次 for 循環都需要進行加鎖和釋放鎖的操作,性能是很低的;但如果我們直接在 for 循環的外層加一把鎖,那么對于同一個對象操作這段代碼的性能就會提高很多,如下偽代碼所示:

    public String method() {StringBuilder sb = new StringBuilder();// 偽代碼:加鎖操作for (int i = 0; i < 10; i++) {sb.append("i:" + i);}// 偽代碼:解鎖操作return sb.toString(); }

    鎖粗化的作用:如果檢測到同一個對象執行了連續的加鎖和解鎖的操作,則會將這一系列操作合并成一個更大的鎖,從而提升程序的執行效率

    4.自適應自旋鎖

    自旋鎖是指通過自身循環,嘗試獲取鎖的一種方式,偽代碼實現如下:

    // 嘗試獲取鎖 while(!isLock()){}

    自旋鎖優點在于它避免一些線程的掛起和恢復操作,因為掛起線程和恢復線程都需要從用戶態轉入內核態,這個過程是比較慢的,所以通過自旋的方式可以一定程度上避免線程掛起和恢復所造成的性能開銷

    但是,如果長時間自旋還獲取不到鎖,那么也會造成一定的資源浪費,所以我們通常會給自旋設置一個固定的值來避免一直自旋的性能開銷。然而對于 synchronized 關鍵字來說,它的自旋鎖更加的“智能”,synchronized 中的自旋鎖是自適應自旋鎖,這就好比之前一直開的手動擋的三輪車,而經過了 JDK 1.6 的優化之后,我們的這部“車”,一下子變成自動擋的蘭博基尼了。

    自適應自旋鎖是指,線程自旋的次數不再是固定的值,而是一個動態改變的值,這個值會根據前一次自旋獲取鎖的狀態來決定此次自旋的次數。比如上一次通過自旋成功獲取到了鎖,那么這次通過自旋也有可能會獲取到鎖,所以這次自旋的次數就會增多一些,而如果上一次通過自旋沒有成功獲取到鎖,那么這次自旋可能也獲取不到鎖,所以為了避免資源的浪費,就會少循環或者不循環,以提高程序的執行效率。簡單來說,如果線程自旋成功了,則下次自旋的次數會增多,如果失敗,下次自旋的次數會減少。

    總結

    本文我們介紹了 4 種優化 synchronized 的方案,其中鎖膨脹和自適應自旋鎖是 synchronized 關鍵字自身的優化實現,而鎖消除和鎖粗化是 JVM 虛擬機對 synchronized 提供的優化方案,這些優化方案最終使得 synchronized 的性能得到了大幅的提升,也讓它在并發編程中占據了一席之地。

    參考 & 鳴謝

    www.cnblogs.com/aspirant/p/11470858.html

    zhuanlan.zhihu.com/p/29866981

    tech.meituan.com/2018/11/15/java-lock.html

    本系列原創文章推薦

    1.線程的故事:我的3位母親成就了優秀的我!

    2.線程池的7種創建方式,強烈推薦你用它...

    3.輕量級鎖一定比重量級鎖快嗎?

    4.這樣終止線程,竟然會導致服務宕機?

    5.漫畫:如何證明sleep不釋放鎖,而wait釋放鎖?

    6.池化技術到達有多牛?看了線程和線程池的對比嚇我一跳!

    7.求求你,別再用wait和notify了!

    8.Semaphore自白:限流器用我就對了!

    9.CountDownLatch:別浪,等人齊再團!

    10.CyclicBarrier:人齊了,老司機就發車了!

    11.Java中用戶線程和守護線程區別這么大?

    12.ThreadLocal不好用?那是你沒用對!

    13.ThreadLocal內存溢出代碼演示和原因分析!

    14.SimpleDateFormat線程不安全的5種解決方案!

    15.synchronized 加鎖 this 和 class 的區別!

    16.synchronized 優化手段之鎖膨脹機制!

    總結

    以上是生活随笔為你收集整理的synchronized 中的 4 个优化,你知道几个?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。