多執行緒知識梳理(2) - synchronized 三部曲之基本使用
一、為什麼要使用 synchronized
使用synchronized
的原因在於:它能夠確保多個執行緒在同一時刻,只能有一個執行緒處於方法或者同步塊中,它保證了執行緒對變數訪問的可見性和排他性。
二、synchronized 原理
在JDK 1.6
之前,synchronized
的實現是基於物件上的監視器,這也被稱為重量鎖。預設情況下,每一個物件都有一個關聯的Monitor
,而每個Monitor
包含了一個EntryCount
計數器,它是synchronized
實現可重入的關鍵。
在JDK 1.6
之後,對鎖進行了一系列優化的措施,通過引入自旋鎖、適應性自旋鎖、鎖消除、鎖粗化、偏向鎖、輕量級鎖等技術來減少鎖操作的開銷。
這些優化措施最終的目的是減少鎖操作的開銷,然而它所改變的只是鎖的實現方式,但是加鎖和解鎖這一基本原則是沒有改變的。這篇文章主要是介紹synchronized
的使用,因此,在後面的介紹中,我們還是按照比較容易理解的重量鎖的方式進行分析,在之後的文章中,我們再來談一下優化後的實現策略。
2.1 進入同步方法或者程式碼塊
當一個執行緒執行某個物件的同步方法或者程式碼塊時,會先檢查這個物件所關聯的Monitor's EntryCount
是否為0
:
- 如果
EntryCount
為0
,那麼該執行緒就會將Monitor’s EntryCount
設定為1
,併成為該Monitor
的所有者,接著執行該方法或者程式碼塊中的語句。 - 如果
EntryCount
不為0
,這時會去檢查物件所關聯的Monitor
的持有者是哪一個執行緒: - 第一種情況:持有該
Monitor
的執行緒就是當前正在嘗試獲取Monitor
的執行緒,那麼將EntryCount
的數值加1
,繼續執行方法或者程式碼塊中的語句。 - 第二種情況:持有該
Monitor
的是其它的執行緒,那麼該執行緒進入阻塞狀態,直到EntryCount
的數值變為0
。
2.2 退出同步方法或者程式碼塊
當一個執行緒從同步方法或者程式碼塊退出時,會將EntryCount
減1
,如果EntryCount
變為0
,那麼該執行緒會釋放它所持有的Monitor
。之前那些阻塞在synchronized
的執行緒會嘗試去獲取Monitor
,成功獲取Monitor
的執行緒可以進入同步方法或者程式碼塊。
三、synchronized 使用
對於synchronized
的使用,我們有兩種分類方法:
- 根據使用場景分類
- 根據
Monitor
關聯的物件分類。
3.1 根據使用場景分類
很多介紹synchronized
的文章,都是通過使用場景進行分類的,一般來說可以分為如下四種使用場景,而每種場景下根據Monitor
所關聯的物件不同,又會衍生出另外的用法:
- 靜態方法
//靜態方法,使用的是Class類鎖
synchronized public static void staticMethod() {}
- 靜態方法程式碼塊
private static final byte[] mStaticLockByte = new byte[1];
//靜態方法程式碼塊1,使用的是Class類鎖
public static void staticBlock1() {
synchronized (SynchronizedObject.class) {}
}
//靜態方法程式碼塊2,使用的是內部靜態變數鎖
public static void staticBlock2() {
synchronized (mStaticLockByte) {}
}
- 普通方法
//普通方法,使用的是呼叫該方法的物件鎖
synchronized public void method() {}
- 普通方法程式碼塊
private static final byte[] mStaticLockByte = new byte[1];
private final byte[] mLockByte = new byte[1];
//普通方法程式碼塊1,使用的是Class類鎖
public void block1() {
synchronized (SynchronizedObject.class) {}
}
//普通方法程式碼塊2,使用的是mLockByte的變數鎖
public void block2() {
synchronized (mLockByte) {} //變數需要宣告為final
}
//普通方法程式碼塊3,使用的是mStaticLockByte的變數鎖
public void block3() {
synchronized (mStaticLockByte) {}
}
//普通方法程式碼塊4,使用的是呼叫該方法的物件鎖
public void block4() {
synchronized (this) {}
}
3.2 根據 Monitor 關聯的物件分類
根據使用場景進行分類,主要是為了讓大家知道如何使用synchronized
關鍵字,然而要真正地理解synchronized
,就需要結合第二節談到的synchronized
原理,其實3.1
中談到的多種場景,都是和Monitor
有關,那麼從和Monitor
關聯的物件來看,我們重新對3.1
中的8
種場景重新進行分類:
-
Class
物件: - 靜態方法
- 靜態方法程式碼塊1 -
SynchronizedObject.class
- 普通方法程式碼塊1 -
SynchronizedObject.class
- 呼叫方法的物件
- 普通方法
- 普通方法程式碼塊4 -
this
- 靜態物件
- 靜態方法程式碼塊2 -
mStaticLockByte
- 普通方法程式碼塊3 -
mStaticLockByte
- 非靜態物件
- 普通方法程式碼塊1 -
mLockByte
如果使用場景屬於上面的同一個分類當中,那麼才有可能產生執行緒阻塞在synchronized
關鍵字的情況,舉一個例子,如果A
執行緒通過靜態方法訪問(分類一)並且沒有從該方法退出:
- 這時
B
執行緒是通過一個物件的普通方法來訪問(分類二),那麼是不會阻塞的,這是因為呼叫該方法的物件所關聯的Monitor
沒有被持有。 - 如果
B
執行緒使用的是靜態方法程式碼塊來訪問,而該靜態方法程式碼塊使用的是SynchronizedObject.class
來修飾(分類一),由於這兩種使用場景是屬於同一個分類,那麼就會B
執行緒就會進入阻塞狀態,這是因為SynchronizedObject
類所關聯的Monitor
已經被A
執行緒持有了。
四、小結
從表面上來看,synchronized
的使用可以簡單地分為同步方法和同步程式碼塊,但是究竟在什麼情況下會導致一個執行緒在synchronized
上阻塞,則需要分析synchronized
方法所嘗試獲取的Monitor
的是否已經被其它執行緒持有了。
相關文章
- 多執行緒知識梳理(2) synchronized 三部曲之基本使用執行緒synchronized
- 多執行緒知識梳理(3) synchronized 三部曲之鎖優化執行緒synchronized優化
- 多執行緒知識梳理(4) synchronized 三部曲之等待 通知模型執行緒synchronized模型
- 《面試補習》- 多執行緒知識梳理面試執行緒
- 多執行緒基礎知識點梳理執行緒
- 多執行緒知識梳理(5) 執行緒池四部曲之 Executor 框架執行緒框架
- 多執行緒知識梳理(6) 執行緒池四部曲之 ThreadPoolExecutor執行緒thread
- java多執行緒之(synchronized)Java執行緒synchronized
- java多執行緒之執行緒的基本使用Java執行緒
- 執行緒基本知識點執行緒
- 多執行緒知識梳理(8) – volatile 關鍵字執行緒
- 多執行緒知識梳理(8) - volatile 關鍵字執行緒
- 多執行緒知識梳理(7) ConcurrentHashMap 實現原理執行緒HashMap
- Java多執行緒之synchronized理論Java執行緒synchronized
- Java多執行緒之synchronized詳解Java執行緒synchronized
- Java多執行緒之執行緒同步【synchronized、Lock、volatitle】Java執行緒synchronized
- Java多執行緒——synchronized的使用示例Java執行緒synchronized
- 多執行緒基礎知識執行緒
- @Java | Thread & synchronized – [ 執行緒同步鎖 基本使用]Javathreadsynchronized執行緒
- Java多執行緒(三):SynchronizedJava執行緒synchronized
- java多執行緒3:synchronizedJava執行緒synchronized
- OkHttp 知識梳理(2) OkHttp 原始碼解析之非同步請求 & 執行緒排程HTTP原始碼非同步執行緒
- 多執行緒基礎之synchronized和volatile執行緒synchronized
- Java多執行緒之synchronized的小介紹Java執行緒synchronized
- Java多執行緒相關知識Java執行緒
- Java多執行緒之二(Synchronized)Java執行緒synchronized
- Java基礎知識回顧之五 ----- 多執行緒Java執行緒
- Java多執行緒之synchronized增強版——ReentrantLockJava執行緒synchronizedReentrantLock
- 多執行緒基礎必要知識點!看了學習多執行緒事半功倍執行緒
- 多執行緒知識梳理(1) 併發程式設計的藝術筆記執行緒程式設計筆記
- 多執行緒之初識執行緒執行緒
- 大話Android多執行緒(二) synchronized使用解析Android執行緒synchronized
- 多執行緒之應知應會執行緒
- 多執行緒(三)、執行緒池 ThreadPoolExecutor 知識點總結執行緒thread
- 多執行緒(二)、內建鎖 synchronized執行緒synchronized
- JAVA多執行緒-基礎篇-synchronizedJava執行緒synchronized
- Android小知識-Java多執行緒相關(Lock使用)AndroidJava執行緒
- 執行緒和程式基礎以及多執行緒的基本使用(iOS)執行緒iOS