多線程第四節_synchronized

1. 設計同步器的意義

	多線程中,有可能會出現同一個線程訪問同一個共享資源,我們稱這個資源爲臨近資源,這種資源可以使對象,變量,文件。由於線程訪問的過程不可控,所以需要採用同步機制來協同對象可變狀態的訪問

1.1 如何解決線程併發安全問題

	序列化訪問臨界資源。在同一時刻只有一個線程可以訪問臨界資源,也稱作同步互斥訪問。java中提供了倆種方式實現同步互斥訪問 synchronized,lock;

2. synchronized原理詳解

	synchronized內置鎖是一種對象鎖,鎖的對象而非引用,作用力度是對象,可重入;加鎖的方式有三種,1同步實例方法,鎖當前實例對象;2同步類方法,鎖的當前類對象;3同步代碼塊,鎖的是括號裏的對象

2.1 synchronized的底層原理

	synchronized是基於jvm內置鎖實現,通過內部的monitor(監視器鎖)實現,基於進入退出monitor對象實現方法與代碼同步,monitor的實現依賴底層操作系統的mutex lock(互斥鎖)實現,它是一個重量級鎖,性能低,當然jvm1.5後進行了優化,如所粗化,鎖消除,輕量級鎖,偏向鎖,適應性自旋等減少鎖開銷。內置鎖的性能基本和lock持平。
     synchronized關鍵字被編譯成字節碼後會被翻譯成monitorenter和monitorexit倆條指令分別在同步塊邏輯代碼的其實位置與結束位置

1655796719467

1655796739636

2.2 monitor監視鎖

任何一個對象都有一個monitor與之關聯,當一個monitor被持有後,他將處於鎖定狀態;
    monitorenter:每個對象都是一個監視器鎖(monitor)。當monitor被佔用時就會處於鎖定狀態,線程執行 monitorenter指令時嘗試獲取monitor的所有權,過程如下他的執行過程如下:
    a 如果monitor的進入數爲0 ,則該線程進入monitor,然後進入數設置爲1,該線程既爲monitor的所有者
    b 如果線程已經佔有了monitor,只是重新進入,則monitor進入加1
    c 如果其他線程佔用了monitor,則該線程進入阻塞狀態,直到monitor的進入數爲0,在嘗試獲取monitor的所有權
 	
    monitorexit:執行monitorexit的線程必須對應的monitor持有者,執行指令時,monitor的進入數減一,如果減一後進入數爲0,則線程退出monitor,不再是這個monitor的持有者,其他被這個monitor阻塞的線程可以嘗試進入獲取這個monitor的所有權。
    
    通過上面兩段描述,我們應該能很清楚的看出Synchronized的實現原理,Synchronized的語義底層是通過一個monitor的對象來 完成,其實wait/notify等方法也依賴於monitor對象,這就是爲什麼只有在同步的塊或者方法中才能調用wait/notify等方法,否則 會拋出java.lang.IllegalMonitorStateException的異常的原因。
看一個案例

1655797449315

1655797458283

1655797537922

2.3 什麼是monitor

	可以理解成一個同步工具,或者一種同步機制,通常被描述爲一個對象。與一切皆對象一樣,所有的java對象天生的monitor,每一個java對象都有成爲monitor的潛質,因爲java設計中,每一個java對象自產生開始就帶了一把看不見的鎖,它叫內部鎖或者monitor鎖,也就是長說的synchronize對象鎖,markword的鎖標識爲10,其中指針指向的是monitor對象的起始地址。在Java虛擬機(HotSpot)中,Monitor是由ObjectMonitor實現的,其主要數據結構如下(位於 HotSpot虛擬機源碼ObjectMonitor.hpp文件,C++實現的):

1655798994178

1655799035294

3. 對象的內存佈局

	hospot虛擬機中,對象在內存中存儲的佈局分爲三個區域,對象頭hearder,實例數據instance data,對其填充 padding
    1 對象頭,比如hash嗎,對象所屬的年代,對象鎖,鎖狀態標誌,
    2 實例數據,存放類的屬性數據信息
    3 對其填充,虛擬機要求對象起始地址必須是8字節的整數倍,只是爲了對齊字節

1655799213322

3.1 對象頭

	hotspot虛擬機的對象頭包含倆部分信息,Markword,存儲對象自身的運行時數據,如哈希嗎,gc分代年齡,鎖狀態標誌,線程持有的鎖,偏向線程id,偏向時間戳等它是實現輕量級鎖和偏向鎖的關鍵

1655799345713

1655799356574

1655799381957

3.2 對象頭分析工具

1655799398386

3.3 鎖膨脹升級過程

	鎖的狀態總共有四種,無鎖狀態、偏向鎖、輕量級鎖和重量級鎖。隨着鎖的競爭,鎖可以從偏向鎖升級到輕量級鎖,再升級的重 量級鎖,但是鎖的升級是單向的,也就是說只能從低到高升級,不會出現鎖的降級。從JDK 1.6 中默認是開啓偏向鎖和輕量級鎖 的,可以通過-XX:-UseBiasedLocking來禁用偏向鎖。下圖爲鎖的升級全過程:

1655799479773

3.3.1 偏向鎖

1655799504256

3.3.2 輕量級鎖

1655799519680

3.3.3 自旋鎖

1655799538816

3.3.4 鎖消除

1655799599089

3.3.5 逃逸分析

1655799618636

1655799686811

1655799699684

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章