java線程:互斥鎖與讀寫鎖

兩種互斥鎖機制: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();           }       }   }  

相關文章
相關標籤/搜索