JUC同步鎖(五)
根據鎖的新增到Java中的時間,Java中的鎖,可以分為“同步鎖”和“JUC包中的鎖”。
一、同步鎖--synchronized關鍵字
通過synchronized關鍵字來進行同步,實現對競爭資源的互斥訪問的鎖。
同步鎖的原理是,對於每一個物件,有且僅有一個同步鎖;不同的執行緒能共同訪問該同步鎖。但是,在同一個時間點,該同步鎖能且只能被一個執行緒獲取到。這樣,獲取到同步鎖的執行緒就能進行CPU排程,從而在CPU上執行;而沒有獲取到同步鎖的執行緒,必須進行等待,直到獲取到同步鎖之後才能繼續執行。這就是,多執行緒通過同步鎖進行同步的原理!
二、JUC包中的鎖
相比同步鎖,JUC包中的鎖的功能更加強大,它為鎖提供了一個框架,該框架允許更靈活地使用鎖
JUC包中的鎖,包括:
- Lock介面
- ReadWriteLock介面
- Condition介面
- ReentrantLock獨佔鎖
- ReentrantReadWriteLock讀寫鎖
- CountDownLatch
- CyclicBarrier
- Semaphore
- AbstractOwnableSynchronizer抽象類
- AbstractQueuedSynchronizer抽象類
- AbstractQueuedLongSynchronizer抽象類
下面以簡單的例項對兩種鎖進行介紹:
(1)簡單的鎖synchronized:
public class ThreadTest {
public void test(){
synchronized(this){
//do something
}
}
}
(2)lock鎖實現
public class ThreadTest { Lock lock = new Lock(); public void test(){ // 當前執行緒會被阻塞,直到該Lock物件的unlock()方法被呼叫 lock.lock(); //do something // 釋放鎖 lock.unlock(); } }
lock()方法會對Lock例項物件進行加鎖,因此所有對該物件呼叫lock()方法的執行緒都會被阻塞,直到該Lock物件的unlock()方法被呼叫。
Lock鎖實現:
public final synchronized void lock() throws InterruptedException{
// 當isLocked為true時,呼叫lock()的執行緒在wait()呼叫上阻塞等待。
while(this.locked) {
this.wait();
}
// 讓其它正在呼叫lock()方法的執行緒能夠在Lock例項上加鎖。
this.locked = true;
}
public final synchronized void unlock() {
this.locked = false;
this.notifyAll();
}
當isLocked為true時,呼叫lock()的執行緒在wait()呼叫上阻塞等待。為防止該執行緒沒有收到notify()呼叫也從wait()中返回,這個執行緒會重新去檢查isLocked條件以決定當前是否可以安全地繼續執行還是需要重新保持等待,而不是認為執行緒被喚醒了就可以安全地繼續執行了。如果isLocked為false,當前執行緒會退出while(isLocked)迴圈,並將isLocked設回true,讓其它正在呼叫lock()方法的執行緒能夠在Lock例項上加鎖。
三、詳解JUC包中的各個鎖
鎖的框架圖如下:
(1)Lock 介面
Lock為介面型別,Lock實現提供了比使synchronized方法和語句可獲得的更廣泛的鎖定操作。此實現允許更靈活的結構,可以具有差別很大的屬性,可以支援多個相關的Condition物件。
JUC 包中的 Lock 介面支援那些語義不同 (重入、公平等) 的鎖規則。所謂語義不同,是指鎖可是有 “公平機制的鎖”、”非公平機制的鎖”、”可重入的鎖” 等等。”公平機制” 是指 “不同執行緒獲取鎖的機制是公平的”,而 “非公平機制” 則是指 “不同執行緒獲取鎖的機制是非公平的”,”可重入的鎖” 是指同一個鎖能夠被一個執行緒多次獲取。
(2)ReadWriteLock
ReadWriteLock為介面型別, 維護了一對相關的鎖,一個用於只讀操作,另一個用於寫入操作。只要沒有 writer,讀取鎖可以由多個 reader 執行緒同時保持。寫入鎖是獨佔的。
ReadWriteLock 介面以和 Lock 類似的方式定義了一些讀取者可以共享而寫入者獨佔的鎖。JUC 包只有一個類實現了該介面,即 ReentrantReadWriteLock,因為它適用於大部分的標準用法上下文。但程式設計師可以建立自己的、適用於非標準要求的實現。
(3)Condition
Condition為介面型別,它將 Object 監視器方法(wait、notify 和 notifyAll)分解成截然不同的物件,以便通過將這些物件與任意 Lock 實現組合使用,為每個物件提供多個等待 set (wait-set)。其中,Lock 替代了 synchronized 方法和語句的使用,Condition 替代了 Object 監視器方法的使用。可以通過await(),signal()來休眠/喚醒執行緒。
Condition 需要和 Lock 聯合使用,它的作用是代替 Object 監視器方法,可以通過 await(),signal() 來休眠 / 喚醒執行緒。Condition 介面描述了可能會與鎖有關聯的條件變數。這些變數在用法上與使用 Object.wait 訪問的隱式監視器類似,但提供了更強大的功能。需要特別指出的是,單個 Lock 可能與多個 Condition 物件關聯。為了避免相容性問題,Condition 方法的名稱與對應的 Object 版本中的不同。
(4)LockSupport
LockSupport 提供 “建立鎖” 和“其他同步類的基本執行緒阻塞原語”。
LockSupport 的功能和 “Thread 中的 Thread.suspend()和 Thread.resume()有點類似”,LockSupport 中的 park() 和 unpark() 的作用分別是阻塞執行緒和解除阻塞執行緒。但是 park()和 unpark()不會遇到 “Thread.suspend 和 Thread.resume 所可能引發的死鎖” 問題。
(5)CountDownLatch
CountDownLatch為常用類,它是一個同步輔助類,在完成一組正在其他執行緒中執行的操作之前,它允許一個或多個執行緒一直等待。
(6)ReentrantLock
Reentrant:可重入
ReentrantLock 是獨佔鎖。所謂獨佔鎖,是指只能被獨自佔領,即同一個時間點只能被一個執行緒鎖獲取到的鎖。ReentrantLock 鎖包括 “公平的 ReentrantLock” 和 “非公平的 ReentrantLock”。”公平的 ReentrantLock” 是指 “不同執行緒獲取鎖的機制是公平的”,而 “非公平的 ReentrantLock” 則是指 “不同執行緒獲取鎖的機制是非公平的”,ReentrantLock 是 “可重入的鎖”。
參考連結
本片文章,主要整理自網際網路,便於自己複習知識所用,以下為參考連結!
【1】Java併發程式設計實戰-----“J.U.C”:鎖,lock
【2】JUC包中的鎖
【4】JUC鎖框架綜述