程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java多線程基礎總結八:ReentrantReadWriteLock

Java多線程基礎總結八:ReentrantReadWriteLock

編輯:關於JAVA

說到ReentrantReadWriteLock,首先要做的是與ReentrantLock劃清界限。它和後者都是單獨的實現,彼此之間沒有繼承或實現的關系。 然後就是總結這個鎖機制的特性了:

(a).重入方面其內部的WriteLock可以獲取ReadLock,但是反過來ReadLock想要獲得WriteLock則永遠都不要想。

(b).WriteLock可以降級為ReadLock,順序是:先獲得WriteLock再獲得ReadLock,然後釋放WriteLock,這時候線程將保持Readlock的持 有。反過來ReadLock想要升級為WriteLock則不可能,為什麼?參看(a),呵呵.

(c).ReadLock可以被多個線程持有並且在作用時排斥任何的WriteLock,而WriteLock則是完全的互斥。這一特性最為重要,因為對於高 讀取頻率而相對較低寫入的數據結構,使用此類鎖同步機制則可以提高並發量。

(d).不管是ReadLock還是WriteLock都支持Interrupt,語義與ReentrantLock一致。

(e).WriteLock支持Condition並且與ReentrantLock語義一致,而ReadLock則不能使用Condition,否則拋出 UnsupportedOperationException異常。

以上就是比較重要的,或者衡量是否使用ReentrantReadWriteLock的基礎了。下面還是寫個小例子說明部分內容:

Java代碼

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
  * @author: yanxuxin
  * @date: 2010-1-7
  */
public class ReentrantReadWriteLockSample {

  public static void main(String[] args) {
  testReadLock();
// testWriteLock();
  }

  public static void testReadLock() {
   final ReadWriteLockSampleSupport support = new ReadWriteLockSampleSupport();
  support.initCache();

  Runnable runnable = new Runnable() {
   public void run() {
   support.get("test");
   }
  };

  new Thread(runnable).start();
  new Thread(runnable).start();

  new Thread(new Runnable() {
   public void run() {
   support.put("test", "test");
   }
  }).start();
  }

  public static void testWriteLock() {
   final ReadWriteLockSampleSupport support = new ReadWriteLockSampleSupport();
  support.initCache();

  new Thread(new Runnable() {
   public void run() {
   support.put("key1", "value1");
   }
  }).start();

  new Thread(new Runnable() {
   public void run() {
   support.put("key2", "value2");
   }
  }).start();

  new Thread(new Runnable() {
   public void run() {
   support.get("key1");
   }
  }).start();
  }
}

class ReadWriteLockSampleSupport {
  private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
  private final Lock readLock = lock.readLock();
  private final Lock writeLock = lock.writeLock();

  private volatile boolean completed;
  private Map<String,String> cache;

  public void initCache() {
  readLock.lock();
  if(!completed) {
   // Must release read lock before acquiring write lock
   readLock.unlock(); // (1)
   writeLock.lock(); // (2)
   if(!completed) {
   cache = new HashMap<String,String>(32);
   completed = true;
   }
   // Downgrade by acquiring read lock before releasing write lock
   readLock.lock();  // (3)
   writeLock.unlock(); // (4) Unlock write, still hold read
  }

  System.out.println("empty? " + cache.isEmpty());
  readLock.unlock();
  }

  public String get(String key) {
  readLock.lock();
  System.out.println(Thread.currentThread().getName() + " read.");
  startTheCountdown();
  try{
   return cache.get(key);
  }
  finally{
   readLock.unlock();
  }
  }

  public String put(String key, String value) {
  writeLock.lock();
  System.out.println(Thread.currentThread().getName() + " write.");
  startTheCountdown();
  try{
   return cache.put(key, value);
  }
  finally {
   writeLock.unlock();
  }
  }

  /**
  * A simple countdown,it will stop after about 5s.
  */
  public void startTheCountdown() {
  long currentTime = System.currentTimeMillis();
  for(;;) {
   long diff = System.currentTimeMillis() - currentTime;
   if(diff > 5000) {
   break;
   }
  }
  }
}

這個例子改造自JDK的API提供的示例,其中ReadWriteLockSampleSupport輔助類負責維護一個Map,當然前提是這個Map大部分的多線程 下都是讀取,只有很少的比例是多線程競爭修改Map的值。其中的initCache()簡單的說明了特性(a),(b).在這個方法中如果把注釋(1)和(2) 處的代碼調換位置,就會發現輕而易舉的死鎖了,當然是因為特性(1)的作用了。而注釋(3),(4)處的代碼位置則再次證明了特性 (a),並 且有力的反映了特性(b)--WriteLock在cache初始化完畢之後,降級為ReadLock。另外get(),put()方法在線程獲取鎖之後會在方法中呆上近 5s的時間。

ReentrantReadWriteLockSample中的兩個靜態測試方法則分別測試了ReadLock和WriteLock的排斥性。testReadLock()中,開啟三個線程 ,前兩者試圖獲取ReadLock而後者去獲取WriteLock。執行結果可以看到:ReadWriteLockSampleSupport的get()方法中的打印結果在前兩個 線程中幾乎同時顯示,而put()中的打印結果則要等上近5s。這就說明了,ReadLock可以多線程持有並且排斥WriteLock的持有線程。 testWriteLock()中,也開啟三個線程。前兩個是去獲取WriteLock,最後一個獲取ReadLock。執行的結果是三個打印結果都有近5s的間隔時 間,這說明了WriteLock是獨占的,比較獨!

這篇ReentrantReadWriteLock的總結寫的有點遲了,主要是最近對js和ajax很有興趣,突然覺得css也很好玩。看著網上很多人對技術的 狂熱和個人規劃,我想對我而言:不迷戀技術而是作為興趣,不管是J2EE還是Web前端,不管是移動設備的三方開發還是專業的視頻剪輯技 術,我都希望很自然的感興趣了,有條件了就去狠狠的玩玩。我想我迷戀的只是高性能的計算機和互聯網,哈哈。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved