併發王者課-青銅07:順藤摸瓜-如何從synchronized中的鎖認
歡迎來到《併發王者課》,本文是該系列文章中的第5篇。
在前面的文章中,我們已經體驗過synchronized的用法,並對鎖的概念和原理做了簡單的介紹。然而,你可能已經察覺到,有一個概念似乎總是和synchronized、鎖這兩個概念如影相隨,很多人也比較喜歡問它們之間的區別,這個概念就是Monitor,也叫監視器。
所以,在講解完synchronized、鎖之後,文字將為你講解Monitor,揭示它們之間那些公開的秘密,希望你不再迷惑。
首先,你要明白的是,Monitor作為一種同步機制,它並非Java所特有,但Java實現了這一機制。
為了具象地理解Monitor這一抽象概念,我們先來分析身邊的一個常見場景。
一、從醫院排隊就診機制理解Monitor
相信你一定有過去醫院就診的經歷。我們去醫院時,情況一般是這樣的:
- 首先,我們在門診大廳前臺或自助掛號機進行掛號;
- 隨後,掛號結束後我們找到對應的診室就診:
- 診室每次只能有一個患者就診;
- 如果此時診室空閒,直接進入就診;
- 如果此時診室內有患者正在就診,那麼我們進入候診室,等待叫號;
- 就診結束後,走出就診室,候診室的下一位候診患者進入就診室。
這個就診過程你一定耳熟能詳,理解起來必然毫不費力氣。我們做了一張圖展示圖下:
仔細看這幅圖中的就診過程,如果你理解了這個過程,你就理解了Monitor. 這麼簡單嗎?不要懷疑自己,是的。你竟然早已理解Monitor機制!
不要小看這個機制,它可是生活中的智慧體現。在這個就診機制中,它起到了兩個關鍵性的作用:
- 互斥(mutual exclusion ):每次只允許一個患者進入候診室就診;
- 協作(cooperation):就診室中的患者就診結束後,可以通知候診區的下一位患者。
明白了嗎?你在醫院就診的過程竟然和Monitor的機制幾乎一模一樣。我們換個方式來描述Monitor在電腦科學中的作用:
- 互斥(mutual exclusion ):每次只允許一個執行緒進入臨界區;
- 協作(cooperation):當臨界區的執行緒執行結束後滿足特定條件時,可以通知其他的等待執行緒進入。
而就診過程中的門診大廳、就診室、候診室則恰好對應著Monitor中的三個關鍵概念。其中:
- 門診大廳:所有待進入的執行緒都必須先在**入口(Entry Set)**掛號才有資格;
- 就診室:一個每次只能有一個執行緒進入的特殊房間(Special Room);
- 候診室:就診室繁忙時,進入等待區(Wait Set);
我們把上面的圖稍作調整,就可以看到Monitor在Java中的模樣:
對比來看,相信你已經很直觀地理解Monitor機制。再一回味,你會發現synchronized正是對Monitor機制的一種實現。而在Java中,每一個物件都會關聯一個監視器。
二、從synchronized原始碼感受Monitor
既然synchronized是對Monitor機制的一種實現,為了讓你更有體感,我們可以寫一段極簡程式碼一探究竟。
這段程式碼極為簡單,但是夠用,我們在程式碼中使用了synchronized
關鍵字:
public class SyncMonitorDemo {
public static void main(String[] args) {
Object o = new Object();
synchronized (o) {
System.out.println("locking...");
}
}
}
程式碼寫好後,分別執行javac SyncMonitorDemo.java
和 javap -v SyncMonitorDemo.class
,隨後你就能得到下面這樣的位元組碼:
Classfile SyncMonitorDemo.class
Last modified May 26, 2021; size 684 bytes
MD5 checksum e366920f22845e98c45f26531596d6cf
Compiled from "SyncMonitorDemo.java"
public class cn.tao.king.juc.execises1.SyncMonitorDemo
minor version: 0
major version: 49
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #2.#22 // java/lang/Object."":()V
#2 = Class #23 // java/lang/Object
#3 = Fieldref #24.#25 // java/lang/System.out:Ljava/io/PrintStream;
#4 = String #26 // locking...
#5 = Methodref #27.#28 // java/io/PrintStream.println:(Ljava/lang/String;)V
#6 = Class #29 // cn/tao/king/juc/execises1/SyncMonitorDemo
#7 = Utf8
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcn/tao/king/juc/execises1/SyncMonitorDemo;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Utf8 args
#17 = Utf8 [Ljava/lang/String;
#18 = Utf8 o
#19 = Utf8 Ljava/lang/Object;
#20 = Utf8 SourceFile
#21 = Utf8 SyncMonitorDemo.java
#22 = NameAndType #7:#8 // "":()V
#23 = Utf8 java/lang/Object
#24 = Class #30 // java/lang/System
#25 = NameAndType #31:#32 // out:Ljava/io/PrintStream;
#26 = Utf8 locking...
#27 = Class #33 // java/io/PrintStream
#28 = NameAndType #34:#35 // println:(Ljava/lang/String;)V
#29 = Utf8 cn/tao/king/juc/execises1/SyncMonitorDemo
#30 = Utf8 java/lang/System
#31 = Utf8 out
#32 = Utf8 Ljava/io/PrintStream;
#33 = Utf8 java/io/PrintStream
#34 = Utf8 println
#35 = Utf8 (Ljava/lang/String;)V
{
public cn.tao.king.juc.execises1.SyncMonitorDemo();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcn/tao/king/juc/execises1/SyncMonitorDemo;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: new #2 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."":()V
7: astore_1
8: aload_1
9: dup
10: astore_2
11: monitorenter
12: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #4 // String locking...
17: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: aload_2
21: monitorexit
22: goto 30
25: astore_3
26: aload_2
27: monitorexit
28: aload_3
29: athrow
30: return
Exception table:
from to target type
12 22 25 any
25 28 25 any
LineNumberTable:
line 5: 0
line 6: 8
line 7: 12
line 8: 20
line 9: 30
LocalVariableTable:
Start Length Slot Name Signature
0 31 0 args [Ljava/lang/String;
8 23 1 o Ljava/lang/Object;
}
SourceFile: "SyncMonitorDemo.java"
javap
是JDK自帶的一個反彙編命令。你可以忽略其他不必要的資訊,直接在結果中找到下面這段程式碼:
11: monitorenter
12: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #4 // String locking...
17: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: aload_2
21: monitorexit
看到monitorenter
和monitorexit
指令,相信智慧的你已經看穿一切。
以上就是文字的全部內容,恭喜你又上了一顆星✨
夫子的試煉
- 寫一段包含
synchronized
關鍵字的程式碼,使用javap
命令觀察結果。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/151/viewspace-2807124/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 併發王者課-青銅7:順藤摸瓜-如何從synchronized中的鎖認識Monitorsynchronized
- 併發王者課-青銅5:一探究竟-如何從synchronized理解Java物件頭中的鎖synchronizedJava物件
- 併發王者課-青銅9:防患未然-如何處理執行緒中的異常執行緒
- 併發王者課-青銅8:分工協作-從本質認知執行緒的狀態和動作方法執行緒
- React 從青銅到王者系列教程之倔強青銅篇React
- 併發王者課-青銅03:興利除弊-如何理解多執行緒帶來的安全問題執行緒
- Nvidia Triton使用教程:從青銅到王者
- 併發王者課-青銅10:千錘百煉-如何解決生產者與消費者經典問題
- 從青銅到王者,揭秘 Serverless 自動化函式最佳配置Server函式
- Mozi殭屍網路大規模暴漲,360安全大腦順藤摸瓜,層層破解“證據鏈”
- Java併發指南4:Java中的鎖 Lock和synchronizedJavasynchronized
- 從青銅到王者,10個css3偽類使用技巧和運用CSSS3
- 從青銅到王者:運維的六大段位,你在哪一段?運維
- 悲觀的併發策略——synchronized互斥鎖synchronized
- 併發王者課-鉑金3:一勞永逸-如何理解鎖的多次可重入問題
- 王者併發課-鉑金3:一勞永逸-如何理解鎖的多次可重入問題
- 一名專案經理,從青銅到王者都需要經歷什麼?
- 併發王者課-鉑金6:青出於藍-Condition如何把等待與通知玩出新花樣
- Java 併發開發:內建鎖 SynchronizedJavasynchronized
- 青銅時代
- 王者併發課-鑽石2:分而治之-如何從原理深入理解ForkJoinPool的快與慢
- 大屏視覺化從青銅到王者的進階,你只差了一個「元件複用」 !視覺化元件
- 併發王者課-黃金2:行穩致遠-如何讓你的執行緒免於死鎖執行緒
- 併發王者課-鉑金1:探本溯源-為何說Lock介面是Java中鎖的基礎Java
- 從 synchronized 到 CAS 和 AQS – 徹底弄懂 Java 各種併發鎖synchronizedAQSJava
- 從 synchronized 到 CAS 和 AQS - 徹底弄懂 Java 各種併發鎖synchronizedAQSJava
- 從青銅到王者10個css3偽類使用技巧和運用,瞭解一哈CSSS3
- 併發程式設計的鎖機制:synchronized和lock程式設計synchronized
- Vue 之青銅 I ⭐Vue
- Vue 之青銅 I ⭐⭐Vue
- 【3y】從零單排學Redis【青銅】Redis
- 從此不怕Synchronized鎖synchronized
- 併發王者課-黃金1:兩敗俱傷-互不相讓的執行緒如何導致了死鎖僵局執行緒
- java併發筆記之synchronized 偏向鎖 輕量級鎖 重量級鎖證明Java筆記synchronized
- 併發系列之「Java中的synchronized關鍵字」Javasynchronized
- Node 入門級別的介面(青銅)
- java併發之synchronizedJavasynchronized
- Java併發程式設計:Synchronized底層優化(偏向鎖、輕量級鎖)Java程式設計synchronized優化