JVM對(duì)Java的原生鎖(即synchronized關(guān)鍵字)做了許多優(yōu)化,其中包括:
當(dāng)一個(gè)線程獲取鎖后,JVM會(huì)將鎖的對(duì)象頭標(biāo)記為偏向鎖。此時(shí),該線程可以無需競爭地獲取該鎖。這種情況下,鎖的獲取和釋放不需要額外的開銷,因?yàn)槠蜴i會(huì)記錄線程ID,使得在該線程持有鎖期間,其他線程無法獲取該鎖。只有在其他線程嘗試獲取鎖時(shí),才會(huì)升級(jí)為輕量級(jí)鎖。
當(dāng)多個(gè)線程爭奪鎖時(shí),JVM會(huì)將鎖標(biāo)記為輕量級(jí)鎖。此時(shí),JVM會(huì)在鎖對(duì)象的對(duì)象頭中記錄指向線程棧中鎖記錄的指針,以及用于保存原始對(duì)象的指針。這樣,當(dāng)一個(gè)線程嘗試獲取該鎖時(shí),JVM會(huì)將該線程的棧幀中的鎖記錄與鎖對(duì)象頭中的指針進(jìn)行比較。如果相同,則表示該線程已經(jīng)獲得了該鎖;否則,JVM會(huì)使用CAS操作嘗試將鎖對(duì)象頭中的指針指向當(dāng)前線程的鎖記錄。如果CAS操作成功,表示當(dāng)前線程成功獲得了鎖。否則,表示有其他線程爭奪該鎖,此時(shí)JVM會(huì)將鎖升級(jí)為重量級(jí)鎖。
當(dāng)多個(gè)線程爭奪鎖時(shí),如果無法獲得鎖,則會(huì)升級(jí)為重量級(jí)鎖。此時(shí),JVM會(huì)使用操作系統(tǒng)的互斥量實(shí)現(xiàn)鎖。重量級(jí)鎖的開銷非常大,因?yàn)樾枰M(jìn)行用戶態(tài)與內(nèi)核態(tài)之間的上下文切換。
下面是一個(gè)簡單的代碼演示,展示了偏向鎖、輕量級(jí)鎖和重量級(jí)鎖的使用情況。
public?class?SynchronizedDemo?{????private?int?count?=?0;????public?synchronized?void?increment()?{????????count++;????}????public?static?void?main(String[]?args)?{????????SynchronizedDemo?demo?=?new?SynchronizedDemo();????????for?(int?i?=?0;?i?100000;?i++)?{????????????demo.increment();????????}????????System.out.println(demo.count);????}}
在這個(gè)示例中,我們使用synchronized關(guān)鍵字來對(duì)increment()方法進(jìn)行同步。由于該方法是實(shí)例方法,因此鎖對(duì)象是該實(shí)例對(duì)象。當(dāng)多個(gè)線程同時(shí)訪問該方法時(shí),JVM會(huì)根據(jù)鎖的狀態(tài)來選擇使用偏向鎖、輕量級(jí)鎖或重量級(jí)鎖。具體的選擇過程是由JVM內(nèi)部的鎖升級(jí)算法來決定的,這里不再詳細(xì)展開。
Copyright ? 2013-2021 河南云和數(shù)據(jù)信息技術(shù)有限公司 豫ICP備14003305號(hào) ISP經(jīng)營許可證:豫B-20160281