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();
public V get(K key) {
readLock.lock();
V value;
try {
value = cache.get(key);
} finally {
readLock.unlock();
}
return value;
}
public V put(K key, V value){
writeLock.lock();
try {
cache.put(key, value);
} finally {
writeLock.unlock();
}
return value;
}
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();
}
}
}