Java synchronize!不全面?這篇文章就夠了!

Synchronize 是什麼

synchronized,中文意思為同步,用於多線程資源共享與維護的最常用手段。它通過線程互斥的手段,保存證了資源的原子性。


使用如下:

<code>

synchronized

(

o

) { } /<code>

實現的原理

本文要講的主要是1.6以後的版本,1.6版本針對synchronize做了使用優化,根據使用的情使用不同的鎖。

包括:

偏向鎖
1:當線程取得鎖時, warkword偏向鎖位標記為1,並記錄使用該對象的線程指針。
2:當線程嘗試向 偏向鎖對象 取鎖時, 鎖將升級為輕量級鎖。

輕量級鎖
1.當線程拿不到鎖對象時,線程不會釋放,而是繼續while循環空轉,直到獲取到鎖為止。
2.輕量級鎖的Markword會記錄lock Record的指針,lock Record會記錄對象自旋的次數,當它達到一定自旋次數之後,jvm會將它升級為重量級鎖。

<code>優點:
無需從用戶態轉向內核態,在鎖競爭比較低的情況,線程只需消化幾個時鐘週期就能獲得鎖,所以性能很快。
缺點:
線程自旋是需要消耗cpu性能的,在鎖競爭激烈的情況,空轉的線程數量和自旋的次數會變高,此時會白白浪費cpu時鐘週期。/<code>

重量級鎖
jvm對重量級鎖的實現,是需要依賴操作系統底層的,操作系統底層維護了一個鎖的隊列,當jvm所有重量級鎖的申請,都需要在這個鎖隊列裡面進行排隊,線程需要從用戶態轉向內核態,排隊過程線程被掛起,無需消耗cpu時鐘頻率,直到輪到這個線程獲取鎖時,系統才會喚醒該爭用的線程。

<code>優點:
不消耗cpu,特別時對於大量鎖的爭用時。
缺點:
等待鎖的時間長。/<code>

synchronize 鎖升級過程

如下圖所示:

  1. 初始化,無鎖。
  2. 有且只有一線程取得鎖時,為偏向鎖。
  3. 對象已被鎖,並有其它線程嘗試取鎖時,鎖升級為輕量級鎖。
  4. 鎖狀態為輕量級鎖,並有更多(達到臨界值時)的線程嘗試去取鎖,輕量級鎖將升級為重量級鎖。
Java synchronize!不全面?這篇文章就夠了!

鎖升級過程

線程獲取鎖過程

如下圖所示:

  1. 對象無鎖時。直接取得鎖
  2. 有鎖並且是輕量級鎖,線程自旋取得鎖。
  3. 有鎖並且是重量級鎖,線程阻塞,等待鎖釋放再取得鎖。
  4. 取得鎖後,用完釋放。
Java synchronize!不全面?這篇文章就夠了!

線程獲取鎖過程

鎖狀態與markword

對象鎖的狀態是存在markword記錄的,如下圖所示:

無鎖時,鎖標誌為01,另外存儲了其它各種信息(包括偏向鎖狀態,分代年齡,hashcode)。

偏向鎖時,鎖標誌為01,另外存儲了取得鎖的線程。

輕量鎖時,鎖標誌為00,存儲了線程棧Lock Record的指針。

重量級鎖時,鎖標誌為10,存儲了,重量級鎖的指針。

Java synchronize!不全面?這篇文章就夠了!

鎖狀態與markword

實例

下面將通過一個實例,結合markword一步一步地演示synchronize 鎖的升級過程。

測試過程
  1. 引入JOL打印出對象的結構(關鍵是markword)。
  2. 模擬無鎖,單線程鎖,2個線程,100個級線。
  3. 輸出對應的markword。

pom.xml 配置

<code> 

<

project

xmlns

=

"http://maven.apache.org/POM/4.0.0"

xmlns:xsi

=

"http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation

=

"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"

>

<

modelVersion

>

4.0.0

modelVersion

>

<

groupId

>

SynchronizeTest

groupId

>

<

artifactId

>

SynchronizeTest

artifactId

>

<

version

>

1.0-SNAPSHOT

version

>

<

dependencies

>

<

dependency

>

<

groupId

>

org.openjdk.jol

groupId

>

<

artifactId

>

jol-core

artifactId

>

<

version

>

0.9

version

>

dependency

>

dependencies

>

project

>

/<code>

代碼

<code>

import

org.openjdk.jol.info.ClassLayout;

public

class

ApplicationTest

{

static

volatile

String strMsg =

""

;

static

volatile

String str2Msg =

""

;

public

static

void

main

(String[] args)

throws

InterruptedException

{ Thread.sleep(

5000

); Object o =

new

Object();

new

Thread() {

public

void

run

()

{

while

(

true

) {

if

(str2Msg.equals(strMsg) ==

false

) { str2Msg = strMsg; System.out.print(str2Msg); } } } }.start(); strMsg = ClassLayout.parseInstance(o).toPrintable(); }

public

static

void

SynsTest

(

int

num,

final

Object o)

throws

InterruptedException

{

for

(

int

i =

0

; i < num; i++) { System.out.println(

"啟開第"

+ (i +

1

) +

"線程"

);

new

Thread() {

public

void

run

()

{

synchronized

(o) {

for

(; ; ) { strMsg = ClassLayout.parseInstance(o).toPrintable();

try

{ Thread.sleep(

100

); } }

catch

(InterruptedException e) { e.printStackTrace(); } } } }.start(); } } }/<code>
測試步驟:

第一步:
1、o對象初始化後,直接打印出o對象。解注以下代碼:

<code>  		 
         strMsg = ClassLayout.parseInstance(o).toPrintable();
         
         
         
         
         
         
/<code>

2、運行結果如下圖所示: 狀態位為01,斷定為無鎖


Java synchronize!不全面?這篇文章就夠了!

無鎖

第二步:


1、開啟1個線程取鎖。解注以下代碼:

<code> 		 
         
         
        

SynsTest

(

1

, o); /<code>

2、結果如下圖所示:狀態位為01,後面還記錄著 對應的線程指針,斷定為 偏向鎖


Java synchronize!不全面?這篇文章就夠了!

偏向鎖

第三步:


1、開啟2個線程最鎖。解注以下代碼:

<code>  		 
         
         
         
         
         

SynsTest

(

2

,o); /<code>

2、如下圖所示:狀態位為00,斷定為輕量級鎖


Java synchronize!不全面?這篇文章就夠了!

輕量級鎖

第四步:
1、開始100個線程取鎖。解注以下代碼:

<code> 
         
         
         
         
         
         
         

SynsTest

(

100

,o);/<code>

2、結果如下圖所示:狀態位為10,斷定為重量級鎖


Java synchronize!不全面?這篇文章就夠了!

重量級鎖

PS
因為偏向鎖默認在jvm啟動4秒後才啟動。所以在這裡設置等待5秒。具體的結果與配置有關。本機測試用的環境如下,所有配置都是默認的。

Java synchronize!不全面?這篇文章就夠了!

可以通過以下命令打印出配置的參數:


Java synchronize!不全面?這篇文章就夠了!

小編整理來自:https://blog.csdn.net/richyliu44/article/details/105327885,CSDN博主「Richy Liu」

今天小編整理的這篇乾貨您覺得怎麼樣呢?是否對自己有一定的提升呢,如果您覺得還可以的話,不妨點個關注收藏轉發一下吶!與小編一起進步!您的支持就是小編最大的動力!謝謝啦!關注我!每天更新哦!絕對技術乾貨!


分享到:


相關文章: