1. 程式人生 > >synchronized 和 lock 的使用分析(優缺點對比詳解)

synchronized 和 lock 的使用分析(優缺點對比詳解)

1. synchronized

加同步格式

synchronized (需要一個任意的物件(鎖)){

程式碼塊中放操作共享資料的程式碼。

}

synchronized 缺陷

synchronized 是java 中的一個關鍵字,也就是說是java 語言的內建的特性

如果一個程式碼塊被synchronized 修飾,當一個執行緒獲取了對應的鎖,並執行程式碼塊時,其他執行緒只能一直等待,等待獲取鎖的執行緒釋放鎖,而這裡獲取鎖的執行緒釋放鎖只會有兩種情況:

(1)獲取鎖的執行緒執行完了改程式碼塊,然後執行緒釋放對鎖的佔有

(2)執行緒執行發生異常,此時JAVA會讓執行緒自動釋放鎖

例子1:

     如果這個獲取鎖的執行緒由於要等待IO 或者其他的原因(比如呼叫sleep方法)被阻塞了,但是有沒有釋放鎖,其他執行緒便只能乾巴巴地等待,試想一個,這多麼執行緒在執行效率。

   因此就需要一種機制可以不讓等待的執行緒一直無期限地等待下去(比如只等待一定的時間或者能夠響應中斷),通過lock就可以辦到。

例子2 :

   當有多個執行緒讀寫檔案時,讀操作和寫操作會發生衝突現象,寫操作和讀操作會發生衝突現象,但是讀操作和讀操作不會發生衝突現象。

     但是採用synchronized 關鍵字來實現同步的話,就會導致一個問題:

如果多個執行緒都只是進行讀操作,當一個執行緒在進行讀操作時,其他執行緒只能等待無法進行讀操作。

因此就需要一種機制來使得多個執行緒都只是進行讀操作時,執行緒之間不會發生衝突,通過Lock就可以辦到。

另外,通過lock可以知道執行緒有沒有成功獲取到鎖,這個是synchronized無法辦到的。

總的來說,也就是說lock提供比synchronized更多的功能。

2.lock
lock和synchronized的區別


(1)lock不是java語言內建的,synchronized是java語言的關鍵字,因此是內建特性。lock是一個類,通過這個類可以實現同步訪問;

(2)lock和synchronized有一點非常大的不同,採用synchronized不需要使用者手動的去釋放鎖,當synchronized方法或者程式碼塊執行完畢之後,系統會自動的讓執行緒釋放對鎖的佔有,而lock則必須要使用者去手動釋放鎖,如果沒有主動的釋放鎖,就會可能導致出現死鎖的現象

 

LOCK


首先要說明的就是,通過檢視LOCK 的原始碼可知道,lock是一個介面

lock介面中每個方法的使用:lock()、tryLock()、tryLock(long time, TimeUnit unit)、lockInterruptibly()是用來獲取鎖的。 unLock()方法是用來釋放鎖的。

四個獲取鎖方法的區別:


(1)lock()方法時平常使用的最多的一個方法,就是用來獲取鎖的,如果鎖已經被其他執行緒獲取,則進行等待。

          由於在前面講到如果採用lock,必須主動去釋放鎖,並且在發生異常時,不會自動釋放鎖。因此一般來說,使用lock必須在try{}catch{}塊中進行,並且將釋放鎖的操作放在finally塊中進行,以保證鎖一定被釋放掉,房主死鎖的發生。

 (2)tryLock()方法是有返回值的,他表示用來嘗試獲取鎖,如果獲取成功,則返回true,如果獲取失敗(即鎖已經被其他執行緒獲取),則返回false,也就說這個方法無論如何都會立即返回。在拿不到鎖時不會一直在哪裡等待

(3)tryLock(long time, TimeUnit unit)方法和tryLock()方法時類似的,只不過區別在於這個方法在拿不到鎖時會等待一定時間,在時間限制之內如果還是拿不到鎖,就返回false。如果一開始就拿到鎖或者在等待期間內拿到了鎖,則就返回true。

(4)lockinterruptibly()方法比較特殊,當通過這個方法區獲取鎖時,如果執行緒正在等待獲取鎖,則這個執行緒能夠相應中斷,即中斷執行緒的等待狀態。也就是說,當連個執行緒同時通過lock.lockinterruputibly()向獲取某個鎖時,假如此時執行緒A獲取到了鎖,而執行緒B只有等待,那麼對執行緒呼叫threadB.interrupt()方法能夠中斷執行緒B的等待過程。

注意:當一個執行緒獲取了鎖之後,是不會被interrupt()方法中斷的

因此當通過lockinterruptibly()方法獲取某個鎖時,如果不能獲取到,只有進行等待的情況下,是可以相應中斷的

而用synchronized修飾的話,當一個執行緒處於等待某個鎖的狀態,是無法被中斷的,只有一直等待下去。

ReentrantLock

直接使用lock介面的話,我們需要實現很多方法,不太方便,ReentrantLock是唯一實現了Lock介面的類,並且ReentrantLock提供了更多的方法,ReentrantLock,意思是“可重入鎖”。

ReadWriteLock也是一個介面,在它裡面只定義了兩個方法:

一個用來獲取讀鎖,一個用來獲取寫鎖。也就是說將檔案的讀寫操作分開,分成2個鎖來分配給執行緒,從而使得多個執行緒可以同時進行讀操作。ReentrantReadWriteLock實現了ReadWriteLock介面。

ReentrantReadWriteLock

ReentrantReadWriteLock裡面提供了很多豐富的方法,不過最主要的兩個方法:readlock()和writelock用來獲取讀鎖和寫鎖

注意:

  不過要注意的是,如果有一個執行緒已經佔用了讀鎖,則此時其他執行緒如果要申請寫鎖,則申請寫鎖的執行緒會一直等待釋放讀鎖。

如果有一個執行緒已經佔用了寫鎖,則此時其他執行緒如果申請寫鎖或者讀鎖,則申請的執行緒會一直等待釋放寫鎖。

 

3.LOCK和SYNCHRONIZED的選擇


(1)lock是一個介面,而synchronized是java的關鍵字,synchronized是內建的語言實現;

(2)synchronized在發生異常時,會自動釋放執行緒佔有的鎖,因此不會導致死鎖現象發生;而lock在發生異常時,如果沒有主動通過unlock()去釋放鎖,則很可能造成死鎖現象,因此使用lock()時需要在finally塊中釋放鎖;

(3)lock可以讓等待鎖的執行緒響應中斷,而synchronized卻不行,使用synchronized時,等待的執行緒會一直等待下去,不訥訥狗狗響應中斷

(4)通過lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到

(5)lock可以挺高多個執行緒進行讀操作的效率

在效能上來說,如果競爭資源不激烈,兩者的效能是差不多的,而競爭資源非常激烈是(既有大量執行緒同時競爭),此時lock的效能要遠遠優於synchronized。所以說,在具體使用時適當情況選擇。
 

原文轉載處:https://blog.csdn.net/qq_38704184/article/details/84189446