雙從檢查

1、科普定義java

這篇博文的兩個主角「synchronized」和「讀寫鎖」面試

1)synchronized數據庫

這個同步關鍵字相信你們都用得比較多,在上一篇「多個線程之間共享數據的方式」中也詳細列舉他的應用,在這就很少說只作幾點概括:編程

  • Java提供這個關鍵字,爲防止資源衝突提供的內置支持。當任務執行到被synchronized保護的代碼片斷的時候,它檢查鎖是否可用,而後獲取鎖,執行代碼,釋放鎖。
  • 經常使用這個關鍵字能夠修飾成員方法和代碼塊

2)讀寫鎖緩存

咱們對數據的操做無非兩種:「讀」和「寫」,試想一個這樣的情景,當十個線程同時讀取某個數據時,這個操做應不該該加同步。答案是不必的。只有如下兩種狀況須要加同步:多線程

  • 這十個線程對這個公共數據既有讀又有寫
  • 這十個線程對公共數據進行寫操做
  • 以上兩點歸結起來就一點就是有對數據進行改變的操做就須要同步

因此性能

java5提供了讀寫鎖這種鎖支持多線程讀操做不互斥,多線程讀寫互斥,多線程寫寫互斥。讀操做不互斥這樣有助於性能的提升,這點在java5之前沒有優化

 

二.用一道面試題來具體比較這兩點ui

題目:「白板編程,實現一個緩存系統」spa

題目分析:

 

對這個緩存系統的理解:

間於用戶和數據庫中間的一個環節,咱們知道用戶直接訪問數據庫的時間是遠大於直接訪問內存,因此有了緩存區後用戶訪問數據時 這樣,用戶先訪問緩存區當緩存區有用戶須要的數據時直接拿走,當緩存區沒有這樣的數據,訪問數據庫並把訪問所得的數據放在緩存區,這樣當下一個須要這個數據的用戶就直接訪問內存便可獲得。

核心代碼實現:

首先用synchronized實現

public synchronized Object getData(String key){
        Object result = map.get(key);
        if(result ==null){
            result = "new";//用這步代替訪問數據庫得數據
        }
        return result;
 
}

用讀寫鎖實現

public Object getData(String key){
        rw.readLock().lock();//在讀前先上讀鎖
        Object result = null;
        try{
            result = map.get(key);
                        //這個if比較關鍵,它避免了多餘的幾回對數據哭的讀取
            if(result==null){
                //若是內存中沒有所要數據
                rw.readLock().unlock();
                rw.writeLock().lock();
                if(result==null){
                    try{
                       //咱們用這個代替對數據庫訪問獲得數據的步驟   
                                            result = "new";
                    }finally{
                    rw.writeLock().unlock();
                    }
                    rw.readLock().lock();
                }
            }
        }finally{
            rw.readLock().unlock();
        }
        return result;
 
    }

代碼分析

  1. 用第一種方法處理,整個過程比較粗線條,代碼比較簡單單執行效率很低。這種方法的中心思想是無論你是什麼操做,但凡涉及到公共資源就都給你同步。這麼作能夠是能夠可是並很差。
  2. 第二種用讀寫鎖處理顯然是對前者的一個優化,對第二種方法作以下幾點說明:
  • 關於unlock操做,咱們知道只要是上了鎖就必需要解鎖,可是有這麼一種狀況就是當你上完鎖後在執行解鎖操做前程序出現異常,那這個所可能就一直存在。因此針對這個問題咱們通常將unlock操做放在finally代碼塊中,就能夠保證上了的鎖必定會被解。
  • 上面的兩次if判斷,第一個if相信你們很好理解。但爲何要用第二個if呢?再假設一個場景,如今有十個線程來讀這個數據,而這個數據又不存在與緩存區,那麼這十個線程中最早到的線程將執行「rw.writeLock().lock();」而另外九個線程將被阻塞,當第一個線程讀完之後緩存區實際上已經就有了這個數據,但另外九個阻塞在「rw.writeLock().lock();」若是不加這層if他們會繼續訪問數據庫,因而可知加了這層if對整個過程影響很大。這是比較細節的一點,就這一點Java的API文檔也考慮到了,它的樣例代碼以下:
  • class CachedData {
      Object data;
      volatile boolean cacheValid;
      ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
     
      void processCachedData() {
        rwl.readLock().lock();
        <span style="color: #ff0000;">if (!cacheValid)</span> {
           // Must release read lock before acquiring write lock
           rwl.readLock().unlock();
           rwl.writeLock().lock();
           // Recheck state because another thread might have acquired
           //   write lock and changed state before we did.
          <span style="color: #ff0000;"> if (!cacheValid)</span> {
             data = ...
             cacheValid = true;
           }
           // Downgrade by acquiring read lock before releasing write lock
           rwl.readLock().lock();
           rwl.writeLock().unlock(); // Unlock write, still hold read
        }
     
        use(data);
        rwl.readLock().unlock();
      }
    }
相關文章
相關標籤/搜索