ReentrantReadWriteLock的規則是:多線程
多線程狀況下:讀-寫互斥、寫-讀互斥、寫-寫互斥、讀-讀共享spa
//單個線程 讀-讀 不互斥 r.lock(); r.lock(); System.out.println("讀-讀 不互斥"); r.unlock(); r.unlock(); //多個線程 讀-讀 不互斥 new Thread(() -> { r.lock(); try {Thread.sleep(2000L);} catch (InterruptedException e) {} r.unlock(); }).start(); new Thread(() -> { r.lock(); System.out.println("馬上執行"); r.unlock(); }).start(); //單個線程 讀-寫 互斥,不存在鎖升級 r.lock(); w.lock(); System.out.println("ok"); w.unlock(); r.unlock(); //多個線程 寫-讀 互斥 new Thread(() -> { w.lock(); try {Thread.sleep(10000000L);} catch (InterruptedException e) {} w.unlock(); }).start(); try {Thread.sleep(500L);} catch (InterruptedException e) {}//等第一個線程 new Thread(() -> { r.lock(); System.out.println("我能得到讀鎖"); r.unlock(); }).start();
對於數據比較敏感的場景,線程
讀鎖:在讀取數據時是不能出現屢次讀取不一致的狀況的,這點有點像可重複讀和幻讀,code
寫鎖:寫數據時,又不能同時讀取數據blog
private final Map<String, Data> m = new TreeMap<String, Data>(); private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); public Data get(String key) { r.lock(); try { return m.get(key); } finally { r.unlock(); } } public String[] allKeys() { r.lock(); try { return m.keySet().toArray(); } finally { r.unlock(); } } public Data put(String key, Data value) { w.lock(); try { return m.put(key, value); } finally { w.unlock(); } } public void clear() { w.lock(); try { m.clear(); } finally { w.unlock(); } }
單線程狀況下有個特殊的點:讀-寫不互斥、即降級get
//單個線程 寫-讀 不互斥,降級 w.lock(); r.lock(); System.out.println("ok"); r.unlock(); w.unlock(); //降級後,其餘線程讀不能進來 由於寫鎖並無徹底釋放,若是按照下面這種方式作,那麼降級將變的沒有任何意義,由於你徹底能夠用一把寫鎖就代替了 new Thread(() -> { w.lock(); r.lock(); System.out.println("我已經降級了"); try {Thread.sleep(2000L);} catch (InterruptedException e) {} r.unlock(); w.unlock(); }).start(); new Thread(() -> { r.lock(); System.out.println("我能進去"); r.unlock(); }).start(); //正確的姿式以下,這樣就能保證在寫鎖沒釋放前轉化爲讀鎖,寫鎖緊接着釋放,其餘線程的讀就能夠進去了 new Thread(() -> { w.lock(); r.lock(); w.unlock(); System.out.println("我已經降級了"); try {Thread.sleep(2000L);} catch (InterruptedException e) {} r.unlock(); }).start(); new Thread(() -> { r.lock(); System.out.println("我能進去"); r.unlock(); }).start();
鎖降級能夠幫助咱們拿到當前線程修改後的結果而不被其餘線程所破壞it
鎖降級的典型用法io
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock r = rwl.readLock(); private final Lock w = rwl.writeLock(); w.lock(); //writing r.lock(); w.unlock(); //reading r.unlock();