看似读锁按部就班
概述
本文簡易介紹下讀寫鎖的策略
1.在公平鎖的條件下,所有的鎖都不允許插隊
2.在非公平的條件下:
寫鎖是可以插隊的(寫鎖插隊可以避免饑餓)
讀鎖僅在等待隊列頭結點不是想獲取寫鎖的線程的時候是可以插隊的。?
接下來我會從ReentrantReadWriteLock源碼部分進行說明。
公平鎖的條件下讀寫鎖的策略
我們從ReentrantReadWriteLock 的FairLock中查看策略,如下圖所示。
從紅圈是可以看到讀鎖和寫鎖的阻塞條件都是當隊列中有等待的處理任務。即就是讀鎖和寫鎖是不可以插隊的。
非公平鎖的情況下的讀寫策略
下面我們介紹非公平鎖的情況下,寫鎖是可以插隊,讀鎖只有在頭結點不是寫線程的情況是可以插隊,見下圖所示。
讀寫鎖測試實例代碼
下文從實例代碼來說明讀寫的插隊策略問題
代碼是實現結果為:非公平鎖的條件下,線程1讀,線程2讀,線程3寫,線程4讀,執行結果為線程4在線程3之后
非公平條件下讀鎖插隊代碼
下文代碼演示非公平的條件下,讀鎖進行插隊的實現,見下代碼。
非公平條件下,讀鎖插隊的條件是:當頭結點不是寫鎖時,可以插隊。
import java.util.concurrent.locks.ReentrantReadWriteLock;/*** 本實例演示非公平的條件下,讀鎖插隊的問題(當頭結點不是寫線程的時候)*/ public class NoFairReadWriteDemo {private static ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(false);private static ReentrantReadWriteLock.ReadLock readLock=reentrantReadWriteLock.readLock();private static ReentrantReadWriteLock.WriteLock writeLock=reentrantReadWriteLock.writeLock();public void read(){System.out.println(Thread.currentThread().getName()+"嘗試獲取讀鎖");readLock.lock();try{System.out.println(Thread.currentThread().getName()+"獲取到了讀鎖");}finally {readLock.unlock();}}public void write(){System.out.println(Thread.currentThread().getName()+"嘗試獲取寫鎖");writeLock.lock();try{Thread.sleep(20);System.out.println(Thread.currentThread().getName()+"獲取到了寫鎖");} catch (InterruptedException e) {e.printStackTrace();} finally {writeLock.unlock();}}/*** 線程1獲取寫鎖,其他線程嘗試獲取* 線程1釋放后,隊列頭為線程2,進行讀;線程3也進行讀,測試:線程2在讀取的時候,子線程能否插隊成功* @param args*/public static void main(String[] args) {NoFairReadWriteDemo noFairReadWriteDemo=new NoFairReadWriteDemo();new Thread(()->noFairReadWriteDemo.write(),"線程1").start();new Thread(()->noFairReadWriteDemo.read(),"線程2").start();new Thread(()->noFairReadWriteDemo.read(),"線程3").start();new Thread(()->noFairReadWriteDemo.write(),"線程4").start();new Thread(()->noFairReadWriteDemo.read(),"線程6").start();new Thread(() -> {Thread[] threads=new Thread[1000];for (int i = 0; i < 1000; i++) {int finalI = i;threads[i]=new Thread(()->noFairReadWriteDemo.read(),"子線程"+ finalI);}for (int i = 0; i < 1000; i++) {threads[i].start();}}, "線程6").start();}}?
總結
- 上一篇: 深入理解交互思想
- 下一篇: 读写锁的由奢入俭“易”