一、synchronized鎖的基本原理
synchronized是Java中用于實現線程安全的關鍵字,它可以應用于方法或代碼塊。當一個線程進入synchronized代碼塊時,它將獲得一個鎖,其他線程在嘗試進入同步代碼塊時會被阻塞,直到持有鎖的線程釋放鎖。
synchronized鎖的基本原理是基于對象的監視器(monitor)。每個Java對象都有一個與之關聯的監視器,這個監視器可以被一個線程持有。當一個線程獲取到對象的監視器時,它就可以執行同步代碼塊,其他線程則需要等待。
二、synchronized鎖的升級
盡管synchronized鎖是簡單易用的,但在高并發場景下性能可能不盡如人意。為了提高并發性能,Java引入了一些鎖的升級機制,具體如下:
1、偏向鎖(Biased Locking)
偏向鎖是JDK 6中引入的一種優化機制。它的設計初衷是針對沒有競爭的場景,假設在多數情況下,鎖總是由同一線程多次獲得的。在偏向鎖狀態下,當一個線程獲取到鎖后,會在對象頭中記錄下自己的線程ID。這樣,下次該線程再次獲取鎖時,無需進行同步操作,可以直接進入臨界區。
2、輕量級鎖(Lightweight Locking)
輕量級鎖是JDK 6中對synchronized鎖的升級改進。它的目標是在多個線程交替執行同步塊的情況下,減少傳統的重量級鎖的開銷。輕量級鎖的實現方式是通過CAS(Compare and Swap)操作來實現,將對象頭中的一部分空間作為鎖記錄。當多個線程競爭同一鎖時,會嘗試使用CAS操作來獲取鎖,成功則進入臨界區,失敗則升級為重量級鎖。
3、重量級鎖(Heavyweight Locking)
重量級鎖是synchronized鎖的默認狀態,也是最常見的狀態。當多個線程競爭同一鎖時,會進入重量級鎖狀態。在重量級鎖狀態下,競爭失敗的線程會進入阻塞狀態,被放入鎖的等待隊列中。只有持有鎖的線程釋放鎖后,等待隊列中的線程才有機會獲取鎖進入臨界區。
三、各個鎖的狀態對比
下面對偏向鎖、輕量級鎖和重量級鎖進行簡要對比,以便更好地理解它們之間的差異。
1、偏向鎖
適用場景:適用于多數情況下鎖總是由同一線程多次獲得的場景。獲取鎖的代價:獲取偏向鎖的代價非常低,幾乎沒有額外開銷。競爭情況:當其他線程嘗試競爭偏向鎖時,偏向鎖會自動升級為輕量級鎖。2、輕量級鎖
適用場景:適用于多個線程交替執行同步塊的情況,競爭不激烈的場景。獲取鎖的代價:獲取輕量級鎖的代價相對較低,需要進行CAS操作。競爭情況:當競爭激烈或者CAS操作失敗時,輕量級鎖會自動升級為重量級鎖。3、重量級鎖
適用場景:適用于競爭激烈的場景,多個線程頻繁爭奪同一個鎖的情況。獲取鎖的代價:獲取重量級鎖的代價相對較高,需要進行線程阻塞和喚醒操作。競爭情況:當持有鎖的線程釋放鎖后,等待隊列中的線程按照FIFO順序競爭鎖的獲取。需要注意的是,鎖的升級過程是自動進行的,開發者無需手動干預。JVM會根據鎖的競爭情況自動切換鎖的狀態,以平衡性能和線程公平性。
在實際開發中,選擇合適的鎖取決于具體的應用場景和線程競爭情況。如果線程之間的競爭非常激烈,可以考慮使用其他更高級的鎖機制,如并發包中提供的ReentrantLock、ReadWriteLock等,它們提供了更細粒度的控制和更高的并發性能。