兩種互斥鎖機制:java
一、synchronized數據庫
二、ReentrantLock緩存
ReentrantLock是jdk5的新特性,採用ReentrantLock能夠徹底替代替換synchronized傳統的鎖機制,並且採用ReentrantLock的方式更加面向對象,也更加靈活,網上有不少關於對比二者鎖方式的文章,這裏就很少口舌了,你們baidu、google一下就水落石出了。在本博客中也寫關於這兩種鎖方式實現的經典例子《生產者消費者》。安全
synchronized方式:《java線程:三種方式實現生產者消費者問題_1》多線程
ReentranLock方式:《java線程:三種方式實現生產者消費者問題_2》併發
關於讀寫鎖,用語言解釋不如直接用代碼詮釋,如下經過兩個例子講述讀寫鎖以及讀寫鎖的使用:高併發
例子1:google
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @author amber2012
*
* 讀寫鎖:ReadWriteLock
*
* 在多線程的環境下,對同一份數據進行讀寫,會涉及到線程安全的問題。好比在一個線程讀取數據的時候,另一個線程在
* 寫數據,而致使先後數據的不一致性;一個線程在寫數據的時候,另外一個線程也在寫,一樣也會致使線程先後看到的數據的
* 不一致性。
*
* 這時候能夠在讀寫方法中加入互斥鎖,任什麼時候候只能容許一個線程的一個讀或寫操做,而不容許其餘線程的讀或寫操做,這
* 樣是能夠解決這樣以上的問題,可是效率卻大打折扣了。由於在真實的業務場景中,一份數據,讀取數據的操做次數一般高
* 於寫入數據的操做,而線程與線程間的讀讀操做是不涉及到線程安全的問題,沒有必要加入互斥鎖,只要在讀-寫,寫-寫期
* 間上鎖就好了。
*
* 對於這種狀況,讀寫鎖則最好的解決方案!
*
* 讀寫鎖的機制:
* "讀-讀"不互斥
* "讀-寫"互斥
* "寫-寫"互斥
*
* 即在任什麼時候候必須保證:
* 只有一個線程在寫入;
* 線程正在讀取的時候,寫入操做等待;
* 線程正在寫入的時候,其餘線程的寫入操做和讀取操做都要等待;
*
* 如下是一個緩存類:用於演示讀寫鎖的操做:重入、降級
*/
public class CachedData {
// 緩存都應該是單例的,在這裏用單例模式設計:
private static CachedData cachedData = new CachedData();
private final ReadWriteLock lock = new ReentrantReadWriteLock();//讀寫鎖
private Map<String, Object> cache = new HashMap<String, Object>();//緩存
private CachedData(){
}
public static CachedData getInstance(){
return cachedData;
}
// 讀取緩存:
public Object read(String key) {
lock.readLock().lock();
Object obj = null;
try {
obj = cache.get(key);
if (obj == null) {
lock.readLock().unlock();
// 在這裏的時候,其餘的線程有可能獲取到鎖
lock.writeLock().lock();
try { .net
obj = cache.get(key); //這個是必要的!!!!
if (obj == null) {
obj = "查找數據庫"; // 實際動做是查找數據庫
// 把數據更新到緩存中:
cache.put(key, obj);
}
} finally {
// 當前線程在獲取到寫鎖的過程當中,能夠獲取到讀鎖,這叫鎖的重入,而後致使了寫鎖的降級,稱爲降級鎖。
// 利用重入能夠將寫鎖降級,但只能在當前線程保持的全部寫入鎖都已經釋放後,才容許重入 reader使用
// 它們。因此在重入的過程當中,其餘的線程不會有獲取到鎖的機會(這樣作的好處)。試想,先釋放寫鎖,在
// 上讀鎖,這樣作有什麼弊端?--若是這樣作,那麼在釋放寫鎖後,在獲得讀鎖前,有可能被其餘線程打斷。
// 重入————>降級鎖的步驟:先獲取寫入鎖,而後獲取讀取鎖,最後釋放寫入鎖(重點)
lock.readLock().lock();
lock.writeLock().unlock();
}
}
} finally {
lock.readLock().unlock();
}
return obj;
}
} 線程
例子2:
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.xml.crypto.Data;
/**
* @author amber2012 * * jdk文檔中關於ReentrantReadWriteLock類使用的一個很好的例子,如下是具體的介紹: * * 在使用某些種類的 Collection 時,可使用 ReentrantReadWriteLock 來提升併發性。一般,在預期 collection * 很大,讀取者線程訪問它的次數多於寫入者線程,而且 entail 操做的開銷高於同步開銷時,這很值得一試。例如,如下 * 是一個使用 TreeMap 的類,預期它很大,而且能被同時訪問。 */ public class RWDictionary { private final Map<String, Data> map = new TreeMap<String, Data>(); private final ReadWriteLock rwl = new ReentrantReadWriteLock(); private final Lock readLock = rwl.readLock(); private final Lock writeLock = rwl.writeLock(); public Data get(String key) { readLock.lock(); try { return map.get(key); } finally { readLock.unlock(); } } public String[] allKeys() { readLock.lock(); try { return (String[]) map.keySet().toArray(); } finally { readLock.unlock(); } } public Data put(String key, Data value) { writeLock.lock(); try { return map.put(key, value); } finally { writeLock.unlock(); } } public void clear() { writeLock.lock(); try { map.clear(); } finally { writeLock.unlock(); } } }