《ReentrantReadWriteLock》

1.可重入讀寫鎖的淺析

簡單使用

    private static final ReentrantReadWriteLock readWriteLock       = new ReentrantReadWriteLock();
    private static final ReentrantReadWriteLock.WriteLock writeLock = readWriteLock.writeLock();
    private static final ReentrantReadWriteLock.ReadLock  readLock  = readWriteLock.readLock();

    public static void main(String[] args) {
        Thread t1  = new Thread(BB::read,"t1");
        Thread t2  = new Thread(BB::write,"t2");
        Thread t3  = new Thread(BB::write,"t3");
        Thread t4  = new Thread(BB::read,"t4");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

    public static void read(){
        String name = Thread.currentThread().getName();
        System.out.println(name+"線程進入read方法");
        readLock.lock();
        System.out.println(name+"線程===持有read鎖");
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name+"線程===準備解read鎖");
        readLock.unlock();
    }
    public static void write(){
        String name = Thread.currentThread().getName();
        System.out.println(name+"線程進入write方法");
        writeLock.lock();
        System.out.println(name+"線程===持有write鎖");
        try {
            Thread.sleep(1500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(name+"線程===準備解write鎖");
        writeLock.unlock();
    }
可能出現的結果1:
	    t1線程進入read方法
		t4線程進入read方法
		t1線程===持有read鎖
		t3線程進入write方法
		t2線程進入write方法
		t4線程===持有read鎖
		t4線程===準備解read鎖
		t1線程===準備解read鎖
		t2線程===持有write鎖
		t2線程===準備解write鎖
		t3線程===持有write鎖
		t3線程===準備解write鎖
可能出現的結果2:
        t1線程進入read方法
		t4線程進入read方法
		t2線程進入write方法
		t3線程進入write方法
		t1線程===持有read鎖
		t4線程===持有read鎖
		t4線程===準備解read鎖
		t1線程===準備解read鎖
		t3線程===持有write鎖
		t3線程===準備解write鎖
		t2線程===持有write鎖
		t2線程===準備解write鎖
可能出現的結果3:
		t2線程進入write方法
		t4線程進入read方法
		t3線程進入write方法
		t1線程進入read方法
		t2線程===持有write鎖
		t2線程===準備解write鎖
		t4線程===持有read鎖
		t4線程===準備解read鎖
		t3線程===持有write鎖
		t3線程===準備解write鎖
		t1線程===持有read鎖
		t1線程===準備解read鎖	

  • 從結果可以分析出來可重入讀寫鎖的規則是:併發的時候,讀讀共享讀寫互斥寫寫互斥
  • 讀讀共享:假設第一個進來的線程持有了讀鎖,盡在進行讀操作,接着又來一個線程是讀操作,那麼第二個線程依舊可以持有讀鎖,共享這份被讀鎖鎖定的代碼部分,如果第二個是寫操作就會等待,直到第一個線程讀完,其它的以此類推。

可重入讀寫鎖的應用:實現一個簡單緩存,應對併發問題

**
 * 簡單緩存,無超時實現,使用{@link WeakHashMap}實現緩存自動清理
 * @author Looly
 *
 * @param <K> 鍵類型
 * @param <V> 值類型
 */
public class SimpleCache<K, V> implements Serializable{
	private static final long serialVersionUID = 1L;
	
	/** 池 */
	private final Map<K, V> cache = new WeakHashMap<>();
	
	private final ReentrantReadWriteLock cacheLock = new ReentrantReadWriteLock();
	private final ReadLock readLock   = cacheLock.readLock();
	private final WriteLock writeLock = cacheLock.writeLock();

	/**
	 * 從緩存池中查找值
	 * 
	 * @param key 鍵
	 * @return 值
	 */
	public V get(K key) {
		// 嘗試讀取緩存
		readLock.lock();
		V value;
		try {
			value = cache.get(key);
		} finally {
			readLock.unlock();
		}
		return value;
	}
		
	/**
	 * 放入緩存
	 * @param key 鍵
	 * @param value 值
	 * @return 值
	 */
	public V put(K key, V value){
		writeLock.lock();
		try {
			cache.put(key, value);
		} finally {
			writeLock.unlock();
		}
		return value;
	}

	/**
	 * 移除緩存
	 * 
	 * @param key 鍵
	 * @return 移除的值
	 */
	public V remove(K key) {
		writeLock.lock();
		try {
			return cache.remove(key);
		} finally {
			writeLock.unlock();
		}
	}

	/**
	 * 清空緩存池
	 */
	public void clear() {
		writeLock.lock();
		try {
			this.cache.clear();
		} finally {
			writeLock.unlock();
		}
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章