Java多線程優(yōu)化之偏向鎖原理分析
本文來自Ken Wu's Blog,原文標(biāo)題:《Java偏向鎖實(shí)現(xiàn)原理(Biased Locking)》。
51CTO編輯推薦:Java線程專題
閱讀本文的讀者,需要對(duì)Java輕量級(jí)鎖有一定的了解,知道lock record, mark word之類的名詞。
Java偏向鎖(Biased Locking)是Java 6引入的一項(xiàng)多線程優(yōu)化。它通過消除資源無競爭情況下的同步原語,進(jìn)一步提高了程序的運(yùn)行性能。
輕量級(jí)鎖也是一種多線程優(yōu)化,它與偏向鎖的區(qū)別在于,輕量級(jí)鎖是通過CAS來避免進(jìn)入開銷較大的互斥操作,而偏向鎖是在無競爭場景下完全消除同步,連CAS也不執(zhí)行(CAS本身仍舊是一種操作系統(tǒng)同步原語,始終要在JVM與OS之間來回,有一定的開銷)。
所謂的無競爭場景,舉個(gè)例子,就是單線程訪問帶同步的資源或方法。
偏向鎖實(shí)現(xiàn)原理
偏向鎖,顧名思義,它會(huì)偏向于第一個(gè)訪問鎖的線程,如果在接下來的運(yùn)行過程中,該鎖沒有被其他的線程訪問,則持有偏向鎖的線程將永遠(yuǎn)不需要觸發(fā)同步。
如果在運(yùn)行過程中,遇到了其他線程搶占鎖,則持有偏向鎖的線程會(huì)被掛起,JVM會(huì)嘗試消除它身上的偏向鎖,將鎖恢復(fù)到標(biāo)準(zhǔn)的輕量級(jí)鎖。(偏向鎖只能在單線程下起作用)
通過下圖可以更直觀的理解偏向鎖:
這張圖,省略了輕量級(jí)鎖相關(guān)的幾處步驟,將關(guān)注點(diǎn)更多地聚焦在偏向鎖的狀態(tài)變化上。
偏向模式和非偏向模式,在下面的mark word表中,主要體現(xiàn)在thread ID字段是否為空。
掛起持有偏向鎖的線程,這步操作類似GC的pause,但不同之處是,它只掛起持有偏向鎖的線程(非當(dāng)前線程)。
#T#在搶占模式的橙色區(qū)域說明中有提到,指向當(dāng)前堆棧中最近的一個(gè)lock record(在輕量級(jí)鎖原理一文有講到,lock record是進(jìn)入鎖前會(huì)在stack上創(chuàng)建的一份內(nèi)存空間)。
這里提到的最近的一個(gè)lock record,其實(shí)就是當(dāng)前鎖所在的stack frame上分配的lock record。
整個(gè)步驟是從偏向鎖恢復(fù)到輕量級(jí)鎖的過程。
偏向鎖也會(huì)帶來額外開銷
在JDK6中,偏向鎖是默認(rèn)啟用的。它提高了單線程訪問同步資源的性能。
但試想一下,如果你的同步資源或代碼一直都是多線程訪問的,那么消除偏向鎖這一步驟對(duì)你來說就是多余的。事實(shí)上,消除偏向鎖的開銷還是蠻大的。
所以在你非常熟悉自己的代碼前提下,大可禁用偏向鎖 -XX:-UseBiasedLocking 。