讀寫鎖 ReentrantReadWriteLock(共享鎖+排他鎖)
阿新 • • 發佈:2019-02-10
重入鎖ReentrantLock具有完全互斥排他的效果,即在同一時間,只有獲取鎖的執行緒才能夠執行相應的操作,這樣保證了執行緒安全,但是某些情況下也造成了效率低下的問題,比如被鎖的程式碼塊中只有讀操作,不會修改任何變數,這樣的話就會效率較低,那麼我們可以使用JDK提供的另一種讀寫鎖ReentrantReadWriteLock。
ReentrantReadWriteLock包含兩種鎖,一個是讀操作相關的共享鎖,一個是寫操作相關的排他鎖。
- 多個共享鎖之間不互斥,多個排他鎖之間互斥,共享鎖與排他鎖互斥。
- 當沒有執行緒進行寫操作的時候,多個進行讀操作的執行緒都可以獲取讀鎖;
- 進入寫操作的執行緒只有在獲取寫鎖時才能進行寫操作,並且在同一時間只能有一個執行緒進行寫操作;
- 當寫操作執行緒獲取鎖後,不管是讀操作還是寫操作後要等寫操作執行緒釋放鎖後才能繼續進行。
- 當讀操作執行緒獲取讀鎖後,寫操作同樣要等讀操作執行緒釋放鎖後才能繼續進行。
程式碼測試
讀讀共享,寫寫互斥
import java.util.concurrent.locks.ReentrantReadWriteLock; /** * 讀讀共享,寫寫互斥 */ public class ReentrantReadWriteLockTest1 { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void testMethod(){ try{ lock.readLock().lock(); //讀讀共享 // lock.writeLock().lock(); //寫寫互斥 for(int i = 0; i < 6; i++){ System.out.println("Thread---" + Thread.currentThread().getName() + "--讀鎖讀取資訊中……"); Thread.sleep(1000); } }catch (InterruptedException e){ e.printStackTrace(); } finally { lock.readLock().unlock(); //讀讀共享 // lock.writeLock().unlock(); //寫寫互斥 } } public static void main(String[] args){ ReentrantReadWriteLockTest1 test1 = new ReentrantReadWriteLockTest1(); Runnable runnable = new Runnable() { @Override public void run() { test1.testMethod(); } }; Thread threadA = new Thread(runnable); Thread threadB = new Thread(runnable); threadA.setName("A"); threadB.setName("B"); threadA.start(); threadB.start(); } }
執行結果,使用讀鎖(共享鎖)多個執行緒可以同時執行鎖定的程式碼塊。
將程式碼中的寫鎖註釋去掉,同時註釋掉讀鎖
執行結果,使用寫鎖(排他鎖)多個執行緒只能有一個執行緒在同一時間執行鎖定的程式碼塊。
讀寫互斥,寫讀互斥
import java.util.concurrent.locks.ReentrantReadWriteLock; /** * 讀寫互斥,寫讀互斥. */ public class ReentrantReadWriteLockTest2 { private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public void testRead(){ try{ lock.readLock().lock(); for(int i = 0; i < 6; i++){ System.out.println("Thread---" + Thread.currentThread().getName() + "--讀鎖讀取資訊中……"); Thread.sleep(1000); } } catch(InterruptedException e){ e.printStackTrace(); } finally { lock.readLock().unlock(); } } public void testWrite(){ try{ lock.writeLock().lock(); for(int i = 0; i < 6; i++){ System.out.println("Thread---" + Thread.currentThread().getName() + "--寫鎖寫操作中……"); Thread.sleep(1000); } } catch(InterruptedException e){ e.printStackTrace(); } finally { lock.writeLock().unlock(); } } public static void main(String[] args){ ReentrantReadWriteLockTest2 test2 = new ReentrantReadWriteLockTest2(); Runnable runnableRead = new Runnable() { @Override public void run() { test2.testRead(); } }; Runnable runnableWrite = new Runnable() { @Override public void run() { test2.testWrite(); } }; Thread threadA = new Thread(runnableRead); Thread threadB = new Thread(runnableWrite); threadA.setName("A"); threadB.setName("B"); threadA.start(); threadB.start(); } }
執行結果