世界上不止有黑白兩色,黑與白之間還是灰色的地帶。
在成人的世界裡,大多數人喜歡非黑即白的觀點來看待一個問題,例如《十二公民》中那個剛開始所有人都認定的「一定是富二代殺S了自己的親身父親」,到最後大家理性分析和推測之後發現,事情根本不是大多數人(99.9%)以為的那樣。
我們很容易被他人的說辭所誤導,相信我們願意相信的事,聽我們願意聽的事,然後被輿論所支配,在人云亦云之中漸漸的迷失自我,然後喪失自己獨立思考的能力。
學技術也是一樣,盡信書不如無書,思考才是學習的目的,如果讀書不是為了啟迪自己的智慧,只是為了吹NB,那這個人有很大的概率會一事無成。
那此時我們再回過頭來思考這個問題:輕量級鎖一定比重量級鎖快嗎?
正文在回答這個問題之前,我們先來了解一下:什麼是輕量級鎖?什麼是重量級鎖?
鎖概念輕量級鎖是 JDK 1.6 新增的概念,是相對於傳統的重量級鎖而已的一種狀態,在 JDK 1.5 時,synchronized 是需要通過作業系統自身的互斥量(mutex lock)來實現,然而這種實現方式需要通過用戶態與和核心態的切換來實現,但這個切換的過程會帶來很大的性能開銷,所以在 JDK 1.6 就引入了輕量級鎖來避免此問題的發生。
輕量級鎖執行過程再講輕量級鎖執行過程之前,要先從虛擬機的對象頭開始說起,HotSpot 的對象頭(Object Header)分為兩部分:
Mark Word 區域,用於存儲對象自身的運行時數據,如哈希碼(HashCode)、GC 分帶年齡等;用於存儲指向方法區對象類型數據的指針(如果是數組對象的話,還有一個存儲數組長度的額外信息)。Mark Word 在 32 位系統中,有 32bit 空間,其中:
2bit 用來存儲鎖標誌位,01=可偏向鎖、00=輕量級鎖、10=重量級鎖;再說會輕量級鎖的執行過程,在代碼進入同步塊的時候,如果此對象沒有被線程所佔用,虛擬機會先將此線程的棧幀拷貝一份存儲在當前對象的 Lock Record (鎖記錄) 區域中。
然後虛擬機再使用 CAS (Compare and Swap, 比較並交換) 將本線程的 Mark Word 更新為指向對象 Lock Record 區域的指針,如果更新成功,則表示這個線程擁有了該對象,輕量級鎖添加成功,如果更新失敗,虛擬機會先檢查對象 Mark Word 是否指向了當前線程的線幀,如果是則表明此線程已經擁有了此鎖,如果不是,則表明該鎖已經被其他線程佔用了。如果有兩條以上的線程在爭搶死鎖,那麼鎖就會膨脹為重量鎖,Mark Word 中存儲的就是指向重量級鎖的互斥量指針,後面等待鎖的線程也會進入阻塞狀態。
從以上的過程,我們可以看出輕量級鎖可以理解為是通過 CAS 實現的,理想的情況下是整個同步周期內不存在鎖競爭,那麼輕量鎖可以有效的提高程序的同步性能,然而,如果情況相反,輕量級鎖不但要承擔 CAS 的開銷還要承擔互斥量的開銷,這種情況下輕量級鎖就會比重量級鎖更慢,這就是我們本文的答案。
總結輕量級鎖不是在任何情況下都比重量級鎖快的,要看同步塊執行期間有沒有多個線程搶佔資源的情況,如果有,那麼輕量級線程要承擔 CAS + 互斥量鎖的性能消耗,就會比重量鎖執行的更慢。
關於好與壞和對於錯也是這個道理,有些事今天可能是對的,但明天有可能成錯的了。比如 JDK 1.5 時,你可以說同步線程只有一個方式:synchronized,然而 JDK 1.6 時又添加了 Lock。你昨天說的對的話,在明天可能就變成錯的了。所以對和錯其實並不是那麼絕對,它也沒那麼重要,重要的是你得有獨立思考的能力和辨識對錯認知。
朕已閱