synchronized和Lock的區別


並發編程中,鎖是經常需要用到的,今天我們一起來看下Java中的鎖機制:synchronizedlock

synchronized

Synchronized 是Java 並發編程中很重要的關鍵字,另外一個很重要的是 volatileSyncronized 的目的是一次只允許一個線程進入由他修飾的代碼段,從而允許他們進行自我保護

Synchronized 很像生活中的鎖例子,進入由Synchronized 保護的代碼區首先需要獲取 Synchronized 這把鎖,其他線程想要執行必須進行等待Synchronized 鎖住的代碼區域執行完成后需要把鎖歸還,也就是釋放鎖,這樣才能夠讓其他線程使用。

它提供了⼀種獨占的加鎖⽅式Synchronized獲取和釋放鎖由JVM實現,⽤戶不需要顯示的釋放鎖,⾮常⽅便。然⽽synchronized也有⼀定的局限性:

  • 當線程嘗試獲取鎖的時候,如果獲取不到鎖會⼀直阻塞。屬於是一種悲觀鎖

  • 如果獲取鎖的線程進⼊休眠或者阻塞,除⾮當前線程異常,否則其他線程嘗試獲取鎖必須⼀直等待。

synchronized可以鎖代碼塊、方法和對象

  • 方法聲明時使用,放在范圍操作符之后,返回類型聲明之前。即一次只能有一個線程進入該方法,其他線程要想在此時調用該方法,只能排隊等候。當作用於靜態方法時,鎖住的是Class實例,又因為Class的相關數據存儲在永久帶PermGen(jdk1.8 則是 metaspace),永久帶是全局共享的,因此靜態方法鎖相當於類的一個全局鎖,會鎖所有調用該方法的線程;
private int number;
public synchronized void numIncrease(){
  number++;
}
  • 你也可以在某個代碼塊上使用 Synchronized 關鍵字,表示只能有一個線程進入某個代碼段。
public void numDecrease(Object num){
  synchronized (num){
    number++;
  }
}
  • synchronized后面括號里是一對象,鎖住的是所有以該對象為鎖的代碼塊,此時線程獲得的是對象鎖。
public void test() {
  synchronized (this) {
    // ...
  }
}

lock

Lock 是 Java並發編程中很重要的一個(Lock interface)接口,它要比 synchronized 關鍵字更能直譯"鎖"的概念,Lock需要手動加鎖和手動解鎖,一般通過 lock.lock() 方法來進行加鎖, 通過 lock.unlock() 方法進行解鎖。Lock 還有更強大的功能,例如,它的 tryLock 方法可以非阻塞方式去拿鎖。

Lock接⼝⽐同步⽅法和同步塊提供了更具擴展性的鎖操作。他們允許更靈活的結構,可以具有完全不同的性質,並且可以⽀持多個相關類的條件對象。

它的優勢有:

  • 可以使鎖更公平
  • 可以使線程在等待鎖的時候響應中斷
  • 可以讓線程嘗試獲取鎖,並在⽆法獲取鎖的時候⽴即返回或者等待⼀段時間,不會造成死鎖。
  • 可以在不同的范圍,以不同的順序獲取和釋放鎖

Lock 關聯密切的鎖有 ReentrantLockReadWriteLock

ReetrantLock 實現了Lock接口,它是一個可重入鎖,內部定義了公平鎖與非公平鎖

可重⼊鎖是指同⼀個線程可以多次獲取同⼀把鎖ReentrantLocksynchronized都是可重⼊鎖。

可中斷鎖是指線程嘗試獲取鎖的過程中,是否可以響應中斷synchronized不可中斷鎖,⽽ReentrantLock提供了中斷功能。

公平鎖指多個線程同時嘗試獲取同⼀把鎖時,獲取鎖的順序按照線程達到的順序。

⾮公平鎖允許線程“插隊”synchronized⾮公平鎖,⽽ReentrantLock的默認實現是⾮公平鎖,但是也可以設置為公平鎖。

ReentrantLock它是JDK 1.5之后提供的API層⾯的互斥鎖,需要lock()和unlock()⽅法配合try/finally語句塊來完成。

等待可中斷避免,出現死鎖的情況(如果別的線程正持有鎖,會等待參數給定的時間,在等待的過程中,如果獲取了鎖定,就返回true,如果等待超時,返回false)

公平鎖與⾮公平鎖多個線程等待同⼀個鎖時,必須按照申請鎖的時間順序獲得鎖,Synchronized鎖⾮公平鎖,

ReentrantLock默認的構造函數是創建的⾮公平鎖,可以通過參數true設為公平鎖,但公平鎖表現的性能不是很好。

ReadWriteLock 一個用來獲取讀鎖,一個用來獲取寫鎖。也就是說將文件的讀寫操作分開,分成2個鎖來分配給線程,從而使得多個線程可以同時進行讀操作ReentrantReadWirteLock實現了ReadWirteLock接口,並未實現Lock接口。

總結

  1. synchronized是Java內置的一個關鍵字,Lock是是一個Java接口
  2. synchronized無法判斷獲取鎖的狀態,而lock鎖可以判斷是否獲取到了鎖
  3. synchronized回自動釋放鎖,而lock必須手動釋放鎖。如果不釋放就會變成死鎖
  4. synchronized 線程1(獲得鎖,阻塞)線程2(傻傻地等待),lock就不一定會等待
  5. synchronized 可重入鎖,不可以中斷的,非公平。lock鎖 可重入鎖,可以判斷鎖,公平不公平自己可以設置
  6. synchronized適合鎖少量的代碼同步問題 Lock適合鎖大量的同步代碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM