Synchronized(一)

如噩夢(mèng)一樣的考試結(jié)束了,讓我們剖析一下Synchronized吧??

為了了解java里這個(gè)元老---Synchronized脯颜,我們知道他的幾種使用方式

  • 同步普通方法蝶防,鎖的是當(dāng)前對(duì)象奏属。
public synchronized void SimpleMethod() {
    // code
}
  • 同步靜態(tài)方法福压,鎖的是當(dāng)前 Class 對(duì)象。
public static synchronized void staticMethod() {
    // code
}
  • 同步塊锐朴,鎖的是 () 中的對(duì)象兴喂。
public void Lock() {
    Object o = new Object();
    Synchronized (o) {
            // code
    }
}

寫(xiě)一段簡(jiǎn)單的代碼試試看,底層到底干了什么焚志。

public class TestSynchronize {
    public static void main(String[] args) {
        synchronized (TestSynchronize.class) {
            testSynchronize();
        }
    }

    public synchronized static void testSynchronize() {
        System.out.println("hello synchroinze");
    }
}

臨界區(qū):就是同時(shí)只允許一個(gè)線程訪問(wèn)的代碼區(qū)域衣迷,那么synchronized修飾代碼區(qū)域,就是臨界區(qū)

先用javap看一下酱酬,jvm對(duì)synchronize的處理

從紅色圈圈可以看到壶谒,JVM對(duì)于synchronize,指令級(jí)別增加了monitorenter和moniterexit岳悟。

訪問(wèn)synchronize修飾的代碼塊佃迄,通過(guò)對(duì)象監(jiān)視器( Monitor )進(jìn)行獲取泼差,而這個(gè)獲取過(guò)程排除了其他線程進(jìn)入贵少,保證了同一時(shí)間只有一個(gè)線程來(lái)訪問(wèn)。而沒(méi)有獲取到鎖的線程將會(huì)阻塞到synchronize開(kāi)始處堆缘,直到獲取鎖的線程 monitor.exit 之后才能?chē)L試?yán)^續(xù)獲取鎖滔灶。


對(duì)象監(jiān)視器(Monitor)

Java虛擬機(jī)給每個(gè)對(duì)象和class字節(jié)碼都設(shè)置了對(duì)象監(jiān)聽(tīng)器Monitor,每個(gè)對(duì)象都可以被監(jiān)視吼肥。同時(shí)在Object類中還提供了notify和wait方法來(lái)對(duì)線程進(jìn)行控制录平。


Monitor機(jī)制:

Monitor保證每次只能有一個(gè)線程能進(jìn)入這個(gè)房間進(jìn)行訪問(wèn)被保護(hù)的數(shù)據(jù)麻车,數(shù)據(jù)進(jìn)入房間即為持有Monitor,退出房間即為釋放Monitor斗这。

當(dāng)一個(gè)線程需要訪問(wèn)受保護(hù)的數(shù)據(jù)(即需要獲取對(duì)象的Monitor)時(shí)动猬,它會(huì)首先在entry-set入口隊(duì)列中排隊(duì),如果沒(méi)有其他線程正在持有對(duì)象的Monitor表箭,那么它會(huì)和entry-set隊(duì)列和wait-set隊(duì)列中的被喚醒的其他線程進(jìn)行競(jìng)爭(zhēng)(即通過(guò)CPU調(diào)度)赁咙,選出一個(gè)線程來(lái)獲取對(duì)象的Monitor,執(zhí)行受保護(hù)的代碼段免钻,執(zhí)行完畢后釋放Monitor彼水,如果已經(jīng)有線程持有對(duì)象的Monitor,那么需要等待其釋放Monitor后再進(jìn)行競(jìng)爭(zhēng)极舔。

wait-set:當(dāng)一個(gè)線程擁有Monitor后凤覆,經(jīng)過(guò)某些條件的判斷,這個(gè)時(shí)候需要調(diào)用Object的wait方法拆魏,線程就釋放了Monitor盯桦,進(jìn)入wait-set隊(duì)列,等待Object的notify方法渤刃。當(dāng)該對(duì)象調(diào)用了notify方法 或者notifyAll方法后俺附,wait-set中的線程就會(huì)被喚醒,然后在wait-set隊(duì)列中被喚醒的線程和entry-set隊(duì)列中的線程一起通過(guò)CPU調(diào)度來(lái)競(jìng)爭(zhēng)對(duì)象的Monitor溪掀,最終只有一個(gè)線程能獲取對(duì)象的Monitor事镣。


Object類wait和notify

這里Object提供了Object.wait()和Object.notify()

  • wait方法
    wait有三個(gè)重載方法,分別如下:
wait()
wait(long millis)
wait(long millis, int nanos) 

后面兩個(gè)傳入了時(shí)間參數(shù)(nanos表示納秒)揪胃,表示如果指定時(shí)間過(guò)去還沒(méi)有其他線程調(diào)用notify或者notifyAll方法來(lái)將其喚醒璃哟,那么該線程會(huì)自動(dòng)被喚醒。

當(dāng)前線程必須獲取到了obj的Monitor喊递,調(diào)用其obj.wait()随闪,即wait必須放在同步方法或同步代碼塊中。執(zhí)行wait方法后骚勘,線程進(jìn)入等待狀態(tài)铐伴。

  • notify方法
    notify:只能喚醒一個(gè)正在等待這個(gè)對(duì)象的monitor的線程
    notifyAll:會(huì)喚醒所有正在等待這個(gè)對(duì)象的monitor的線程

    調(diào)用notify方法,必須要等同步代碼塊結(jié)束后才會(huì)釋放Monitor,必須保證其他線程處于wait狀態(tài)俏讹,否則調(diào)用notify沒(méi)有任何效果当宴。也就是wait和notify/notifyAll必須配合使用。


Java對(duì)象頭

Synchronized用的鎖是存在Java對(duì)象頭里的泽疆,這里就需要了解對(duì)象頭的結(jié)構(gòu)

java對(duì)象頭有以下兩種(32位JVM):

  • 普通對(duì)象
|--------------------------------------------------------------|
|                     Object Header (64 bits)                  |
|------------------------------------|-------------------------|
|        Mark Word (32 bits)         |    Klass Word (32 bits) |
|------------------------------------|-------------------------|
  • 數(shù)組對(duì)象
|---------------------------------------------------------------------------------|
|                                 Object Header (96 bits)                         |
|--------------------------------|-----------------------|------------------------|
|        Mark Word(32bits)       |    Klass Word(32bits) |  array length(32bits)  |
|--------------------------------|-----------------------|------------------------|

對(duì)象頭的組成:

  • Mark Word

存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù)(hashcode,gc分代年齡)户矢,大小為JVM一個(gè)字的大小,(32bit/32位虛擬機(jī)殉疼,64bit/64位虛擬機(jī))梯浪,其中后兩位是標(biāo)記位捌年,標(biāo)記位不同,這個(gè)markword表示的含義不同

biased_lock lock 狀態(tài)
0 01 無(wú)鎖
1 01 偏向鎖
0 00 輕量級(jí)鎖
0 10 重量級(jí)鎖
0 11 GC標(biāo)記

不同情況對(duì)應(yīng)的Mark Word如下

|-------------------------------------------------------|--------------------|
|                  Mark Word (32 bits)                  |       State        |
|-------------------------------------------------------|--------------------|
| identity_hashcode:25 | age:4 | biased_lock:1 | lock:2 |       Normal       |
|-------------------------------------------------------|--------------------|
|  thread:23 | epoch:2 | age:4 | biased_lock:1 | lock:2 |       Biased       |
|-------------------------------------------------------|--------------------|
|               ptr_to_lock_record:30          | lock:2 | Lightweight Locked |
|-------------------------------------------------------|--------------------|
|               ptr_to_heavyweight_monitor:30  | lock:2 | Heavyweight Locked |
|-------------------------------------------------------|--------------------|
|                                              | lock:2 |    Marked for GC   |
|-------------------------------------------------------|--------------------|
  • 普通對(duì)象
    identity_hashcode:25位的對(duì)象標(biāo)識(shí)Hash碼挂洛,采用延遲加載技術(shù)礼预。調(diào)用方法System.identityHashCode()計(jì)算,并會(huì)將結(jié)果寫(xiě)到該對(duì)象頭中虏劲。當(dāng)對(duì)象被鎖定時(shí)逆瑞,該值會(huì)移動(dòng)到管程Monitor中。
    age:4位的Java對(duì)象年齡伙单。在GC中获高,如果對(duì)象在Survivor區(qū)復(fù)制一次,年齡增加1吻育。當(dāng)對(duì)象達(dá)到設(shè)定的閾值時(shí)念秧,將會(huì)晉升到老年代
    biased_lock:對(duì)象是否啟用偏向鎖標(biāo)記,只占1個(gè)二進(jìn)制位布疼。為1時(shí)表示對(duì)象啟用偏向鎖摊趾,為0時(shí)表示對(duì)象沒(méi)有偏向鎖。

  • 偏向鎖
    thread:持有偏向鎖的線程ID游两。
    epoch:偏向時(shí)間戳砾层。

  • 輕量級(jí)鎖
    ptr_to_lock_record:指向棧中鎖記錄的指針。

  • 重量級(jí)鎖
    ptr_to_heavyweight_monitor:指向管程Monitor的指針贱案。


PS:今天不早了肛炮,明天繼續(xù)分析Synchronized,四種鎖的狀態(tài)如何切換??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末宝踪,一起剝皮案震驚了整個(gè)濱河市侨糟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌瘩燥,老刑警劉巖秕重,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異厉膀,居然都是意外死亡溶耘,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)服鹅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凳兵,“玉大人,你說(shuō)我怎么就攤上這事菱魔×衾螅” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵澜倦,是天一觀的道長(zhǎng)聚蝶。 經(jīng)常有香客問(wèn)我,道長(zhǎng)藻治,這世上最難降的妖魔是什么碘勉? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮桩卵,結(jié)果婚禮上验靡,老公的妹妹穿的比我還像新娘。我一直安慰自己雏节,他們只是感情好胜嗓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著钩乍,像睡著了一般辞州。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寥粹,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天变过,我揣著相機(jī)與錄音,去河邊找鬼涝涤。 笑死媚狰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的阔拳。 我是一名探鬼主播崭孤,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼糊肠!你這毒婦竟也來(lái)了裳瘪?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤罪针,失蹤者是張志新(化名)和其女友劉穎彭羹,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡臭胜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年肢娘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毡惜。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖斯撮,靈堂內(nèi)的尸體忽然破棺而出经伙,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布帕膜,位于F島的核電站枣氧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏垮刹。R本人自食惡果不足惜达吞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望荒典。 院中可真熱鬧酪劫,春花似錦、人聲如沸寺董。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)遮咖。三九已至滩字,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盯滚,已是汗流浹背踢械。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留魄藕,地道東北人内列。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像背率,于是被迫代替她去往敵國(guó)和親话瞧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 本文出自 Eddy Wiki 寝姿,轉(zhuǎn)載請(qǐng)注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,116評(píng)論 0 14
  • volatile關(guān)鍵字 定義:對(duì)該變量禁止使用CPU緩存,而從主內(nèi)存中讀寫(xiě) 特性: 禁止編碼優(yōu)化(禁止指令重排序)...
    __Amazing閱讀 389評(píng)論 0 0
  • 九種基本類型及封裝類 基本類型booleanbytecharshortintlongdoublefloat 二進(jìn)制...
    0f43ee70035e閱讀 309評(píng)論 1 0
  • 近晚飯的時(shí)候根资,有人敲門(mén)架专,卻原來(lái)是我們小區(qū)業(yè)委會(huì)主任廖阿姨。 廖阿姨手里捧了一束花玄帕,說(shuō)是送給小家伙的外公部脚。一問(wèn)才知道...
    未語(yǔ)輕弦閱讀 384評(píng)論 4 7
  • 八月長(zhǎng)安一定是個(gè)溫柔無(wú)比的人呀 隔著書(shū)一字一句都能體會(huì)到洛枳笑的時(shí)候內(nèi)心的幸福 讀著讀著我自己都不自覺(jué)地笑了起來(lái) ...
    川枝閱讀 169評(píng)論 0 1