首頁 > 軟體

關於synchronized、volatile、ReentrantLock的區別與對比

2023-08-28 18:05:44

聊之前先說一下並行程式設計的3個特性。

並行程式設計特性

  1. 原子性:對共用資源的一組操作,要麼成功要麼失敗,不會出現部分成功部分失敗的情況。
  2. 可見性: 當執行緒獲取到瑣時,會拷貝一份共用資源到本地記憶體,釋放鎖時會將共用資源重新整理到主記憶體中。可見性是指當共用資源發生變化時,其他執行緒都能夠看到這個變化。
  3. 有序性:為了提高效率,編譯器和處理器會對程式碼進行指令重排,單執行緒的情況下,指令重拍不會受到影響,多執行緒情況下可能會影響程式碼執行的正確性。有序性是指程式碼編寫順序和執行順序是一致的。

volatile

volatile 是JVM提供的最輕量級的同步機制,編譯器不會對其進行優化。

特性:

  • volatile 只保證共用資源的可見性有序性
  • 使用volatile修飾共用資源時,如果共用資源變化時,會直接將快取中的資料寫回到主記憶體中去,資料也是從主記憶體中讀取,從而保證了可見性。
  • volatile 底層是通過作業系統的記憶體屏障來實現的,由於使⽤了記憶體屏障,所以會禁⽌指令重排,從而就保證了有序性。

作用的地方:

volatile 只能用來修飾成員變數。

public class VolatileTest {
    
    private volatile static String staticVolatile;
    
    private volatile String memberVolatile;
}

synchronized

synchronized關鍵字是java提供的內建鎖來保證我們對共用資源的同步,它會自動加鎖和釋放鎖,它的鎖是非公平鎖, synchronized關鍵字標記的地方會被編譯器進行優化。synchronized會使執行緒序列執行,可能會造成執行緒阻塞。

特性

  • synchronized關鍵字使執行緒序列化執行,所以保證了並行安全的3個特性,並且還擁有以下兩個特性:
  • 互斥性:同時只有一個執行緒能夠存取synchronized方法或者同步程式碼塊。
  • 可重入性synchronized是可重入鎖,通俗解釋可重入鎖就是當一個執行緒獲取到了某個物件鎖或者類鎖之後,這個執行緒在未釋放鎖之前,再呼叫該鎖的其他synchronized方法或程式碼塊時,不用再次重新獲得鎖。

作用的地方

synchronized關鍵字可用來修飾方法或者程式碼塊。

修飾方法,分為實體方法和靜態方法

  • 修飾實體方法,物件鎖
public  synchronized void objectMethods(){
   .....
}
  • 修飾靜態方法,類鎖
public static  synchronized void staticMethods(){
   .....
 }

修飾程式碼塊

obj為物件的參照 物件鎖

public  void objectMethods(){
	synchronized (obj){
	}
}

Object 為某個類 類鎖

public  void classLock(){
	synchronized (Object.class){
	}
}

ReentrantLock

Lock 是 Java 5提供的一個具有鎖機制的介面,ReentrantLockLock的一個實現,內部是通過AQS(AbstractQueuedSynchronizer)實現的。ReentrantLock翻譯過來是可重入鎖,它和synchronized類似,ReentrantLock 需要手動加鎖和釋放鎖, 相對於synchronized它更加靈活,提供了更多的方法。 ReentrantLock 有公平鎖和非公平鎖兩種方式,預設是使用公平鎖。

特性

ReentrantLock 是可重入的同步鎖,所以它除了具有並行程式設計的三大特性,還具有可重入性。

作用的地方

ReentrantLock 是一個類,它既可以作為成員變數,也可以作為區域性變數使用。做為成員變數和區域性變數時,使用的方式有一點點不同,不管使用哪種方式,最後都別忘了要呼叫unlock() 方法手動釋放鎖。

做為成員變數使用格式:

private Lock globalLock = new ReentrantLock();

public void globalLock(){
    if (globalLock.tryLock()) {
        try {
        } catch (Exception e) {
          
        }finally {
            globalLock.unlock();
        }
    }
}

上面的tryLock() 方法是嘗試獲取鎖,如果獲取成功返回true,否則返回false,也可以換成加了等待時間的 boolean tryLock(long time, TimeUnit unit) 方法,在設定的等待時間內獲取鎖成功則返回true,否則false。

做為區域性變數使用格式:

public void lock(){
     Lock lock = new ReentrantLock();
     lock.lock();
     try {

     }finally {
         lock.unlock();
     }
 }

對比

簡單對比一下三者之間的區別:

volatilesynchronizedReentrantLock
是否是關鍵字
是否需要手動加鎖/釋放鎖
是否能保證並行安全
是否是公平鎖有公平鎖和非公平鎖兩種實現
是否會阻塞執行緒
JVM是否會對其優化
特性可見性、有序性可見性、有序性、原子性可見性、有序性、原子性
使用的地方成員變數方法、程式碼塊成員變數、區域性變數

到此這篇關於關於synchronized、volatile、ReentrantLock的區別與對比的文章就介紹到這了,更多相關synchronized、volatile、ReentrantLock的區別內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com