偏向鎖、輕量級鎖和重量級鎖是jvm為優化synchronized性能引入的三種鎖狀態。1.偏向鎖適用于單線程無競爭場景,通過記錄線程id避免同步操作;2.輕量級鎖用于多線程交替執行場景,采用cas和自旋機制減少阻塞開銷;3.重量級鎖用于多線程激烈競爭場景,依賴操作系統實現線程公平性但帶來較大性能開銷。鎖升級過程不可逆,從偏向鎖升級至輕量級鎖再至重量級鎖,目的是根據不同競爭程度自動選擇最優策略,最終提升程序性能。
Java中的偏向鎖、輕量級鎖和重量級鎖,本質上是JVM為了優化synchronized關鍵字而引入的三種鎖狀態。它們代表了鎖競爭程度由低到高的不同階段,目的是在不同場景下盡可能減少鎖的開銷,提高程序性能。
偏向鎖、輕量級鎖、重量級鎖是synchronized在不同競爭狀態下的表現形式,核心目的是優化同步性能,減少不必要的鎖開銷。理解它們有助于我們編寫更高效的并發程序。
鎖升級的過程是不可逆的,只能由偏向鎖升級為輕量級鎖,再升級為重量級鎖。這個過程是為了在不同場景下選擇最合適的鎖策略,從而提高性能。
立即學習“Java免費學習筆記(深入)”;
為什么需要這些鎖?synchronized不是已經夠用了嗎?
synchronized關鍵字是Java中實現同步的基本方式,但它是一種比較重量級的操作。在多線程環境下,頻繁地獲取和釋放鎖會導致大量的上下文切換,影響程序性能。
偏向鎖、輕量級鎖的引入,就是為了在沒有或很少線程競爭的情況下,減少synchronized帶來的性能開銷。例如,在單線程環境下,偏向鎖可以避免CAS操作,直接將鎖賦予該線程。而在多個線程交替執行的情況下,輕量級鎖可以通過自旋來避免線程阻塞。
synchronized最初實現就是重量級鎖,依賴操作系統的Mutex Lock實現,涉及用戶態和內核態的切換,開銷很大。后來JVM對synchronized進行了優化,引入了偏向鎖和輕量級鎖,來降低鎖的開銷。
偏向鎖:線程“偏愛”的鎖
偏向鎖,顧名思義,就是“偏向”于第一個獲取它的線程。當一個線程獲取到偏向鎖后,會在對象頭中記錄該線程的ID。以后該線程再次進入同步塊時,不需要進行任何同步操作,直接可以繼續執行,從而避免了CAS操作的開銷。
偏向鎖的適用場景是只有一個線程訪問同步塊的情況。如果存在其他線程競爭,偏向鎖會升級為輕量級鎖。
偏向鎖的實現原理:對象頭Mark word中存儲線程ID。當線程再次訪問時,檢查Mark Word中的線程ID是否與當前線程ID一致,如果一致,則認為該線程已經持有鎖,直接執行。
偏向鎖的撤銷:當有其他線程嘗試獲取偏向鎖時,偏向鎖會被撤銷。撤銷的過程需要等到全局安全點(safepoint),暫停擁有偏向鎖的線程,然后檢查該線程是否還在使用該對象。如果不再使用,則將對象頭設置為無鎖狀態,并重新偏向于新的線程;否則,升級為輕量級鎖。
偏向鎖的優點:減少了鎖競爭帶來的開銷,提高了單線程訪問同步塊的性能。
偏向鎖的缺點:適用于單線程場景,如果存在線程競爭,會增加鎖撤銷的開銷。
可以通過JVM參數關閉偏向鎖:-XX:-UseBiasedLocking
輕量級鎖:自旋的嘗試
當偏向鎖遇到競爭時,會升級為輕量級鎖。輕量級鎖并不是真的鎖,而是一種通過CAS(Compare and Swap)操作嘗試獲取鎖的機制。
當線程嘗試獲取輕量級鎖時,會將對象頭的Mark Word復制到線程的Lock Record中,然后嘗試使用CAS操作將對象頭的Mark Word更新為指向Lock Record的指針。如果CAS操作成功,則表示線程獲取到了鎖;如果CAS操作失敗,則表示存在其他線程競爭鎖,當前線程會進入自旋狀態,不斷嘗試CAS操作。
輕量級鎖的適用場景是多個線程交替執行同步塊的情況。自旋可以避免線程阻塞,減少了上下文切換的開銷。但是,如果線程長時間自旋仍然無法獲取到鎖,會消耗大量的CPU資源。
輕量級鎖的實現原理:利用CAS操作和自旋機制嘗試獲取鎖。
輕量級鎖的自旋:自旋是指線程不斷地嘗試獲取鎖,而不是立即阻塞。自旋的次數是有限制的,可以通過JVM參數進行配置:-XX:PreBlockSpin。如果自旋超過一定的次數仍然無法獲取到鎖,輕量級鎖會升級為重量級鎖。
輕量級鎖的優點:減少了線程阻塞帶來的開銷,提高了多線程交替執行同步塊的性能。
輕量級鎖的缺點:如果線程長時間自旋仍然無法獲取到鎖,會消耗大量的CPU資源。
重量級鎖:真正的阻塞
當輕量級鎖自旋一定次數后仍然無法獲取到鎖,會升級為重量級鎖。重量級鎖是真正的鎖,依賴操作系統的Mutex Lock實現。當線程嘗試獲取重量級鎖時,會被阻塞,進入等待隊列。當鎖被釋放時,操作系統會喚醒等待隊列中的一個線程,使其獲取鎖。
重量級鎖的適用場景是多個線程同時競爭鎖的情況。雖然重量級鎖會帶來線程阻塞的開銷,但是可以保證線程的公平性,避免出現饑餓現象。
重量級鎖的實現原理:依賴操作系統的Mutex Lock實現,涉及用戶態和內核態的切換。
重量級鎖的優點:可以保證線程的公平性,避免出現饑餓現象。
重量級鎖的缺點:會帶來線程阻塞的開銷,影響程序性能。
如何選擇合適的鎖?
選擇合適的鎖策略需要根據具體的應用場景進行權衡。
- 如果只有一個線程訪問同步塊,可以使用偏向鎖。
- 如果多個線程交替執行同步塊,可以使用輕量級鎖。
- 如果多個線程同時競爭鎖,可以使用重量級鎖。
在實際開發中,我們不需要手動選擇鎖策略,JVM會根據鎖的競爭程度自動進行鎖升級。但是,了解鎖的升級過程有助于我們編寫更高效的并發程序。
鎖消除和鎖粗化:JVM的優化
除了偏向鎖、輕量級鎖和重量級鎖之外,JVM還提供了一些其他的鎖優化技術,例如鎖消除和鎖粗化。
鎖消除是指JVM在編譯時檢測到一些不可能存在競爭的鎖,會將這些鎖消除掉,從而減少鎖的開銷。
鎖粗化是指JVM將多個相鄰的鎖合并成一個更大的鎖,從而減少鎖的獲取和釋放次數。
這些優化技術都是為了盡可能減少鎖的開銷,提高程序性能。
總而言之,Java中的偏向鎖、輕量級鎖和重量級鎖是JVM為了優化synchronized關鍵字而引入的三種鎖狀態。它們代表了鎖競爭程度由低到高的不同階段,目的是在不同場景下盡可能減少鎖的開銷,提高程序性能。理解這些鎖的原理和適用場景,有助于我們編寫更高效的并發程序。
以上就是Java中偏向鎖、輕量級鎖和重量級鎖的<a