读写锁

ReentrantReadWriteLock

 说到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代码   收藏代码
  1. import java.util.HashMap;  
  2. import java.util.Map;  
  3. import java.util.concurrent.locks.Lock;  
  4. import java.util.concurrent.locks.ReentrantReadWriteLock;  
  5.   
  6. /** 
  7.  * @author: yanxuxin 
  8.  * @date: 2010-1-7 
  9.  */  
  10. public class ReentrantReadWriteLockSample {  
  11.   
  12.     public static void main(String[] args) {  
  13.         testReadLock();  
  14. //      testWriteLock();  
  15.     }  
  16.       
  17.     public static void testReadLock() {  
  18.        final ReadWriteLockSampleSupport support = new ReadWriteLockSampleSupport();  
  19.         support.initCache();  
  20.           
  21.         Runnable runnable = new Runnable() {  
  22.             public void run() {  
  23.                 support.get("test");  
  24.             }  
  25.         };  
  26.           
  27.         new Thread(runnable).start();  
  28.         new Thread(runnable).start();  
  29.           
  30.         new Thread(new Runnable() {  
  31.             public void run() {  
  32.                 support.put("test""test");  
  33.             }  
  34.         }).start();  
  35.     }  
  36.       
  37.     public static void testWriteLock() {  
  38.        final ReadWriteLockSampleSupport support = new ReadWriteLockSampleSupport();  
  39.         support.initCache();  
  40.           
  41.         new Thread(new Runnable() {  
  42.             public void run() {  
  43.                 support.put("key1""value1");  
  44.             }  
  45.         }).start();  
  46.           
  47.         new Thread(new Runnable() {  
  48.             public void run() {  
  49.                 support.put("key2""value2");  
  50.             }  
  51.         }).start();  
  52.           
  53.         new Thread(new Runnable() {  
  54.             public void run() {  
  55.                 support.get("key1");  
  56.             }  
  57.         }).start();  
  58.     }  
  59. }  
  60.   
  61. class ReadWriteLockSampleSupport {  
  62.     private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();  
  63.     private final Lock readLock = lock.readLock();  
  64.     private final Lock writeLock = lock.writeLock();  
  65.       
  66.     private volatile  boolean completed;  
  67.     private Map<String,String> cache;  
  68.       
  69.     public void initCache() {  
  70.         readLock.lock();  
  71.         if(!completed) {  
  72.             // Must release read lock before acquiring write lock  
  73.             readLock.unlock(); // (1)  
  74.             writeLock.lock();  // (2)  
  75.             if(!completed) {  
  76.                 cache = new HashMap<String,String>(32);  
  77.                 completed = true;  
  78.             }  
  79.             // Downgrade by acquiring read lock before releasing write lock  
  80.             readLock.lock();    // (3)  
  81.             writeLock.unlock(); // (4) Unlock write, still hold read  
  82.         }  
  83.           
  84.         System.out.println("empty? " + cache.isEmpty());  
  85.         readLock.unlock();  
  86.     }  
  87.       
  88.     public String get(String key) {  
  89.         readLock.lock();  
  90.         System.out.println(Thread.currentThread().getName() + " read.");  
  91.         startTheCountdown();  
  92.         try{  
  93.             return cache.get(key);  
  94.         }  
  95.         finally{  
  96.             readLock.unlock();  
  97.         }  
  98.     }  
  99.       
  100.     public String put(String key, String value) {  
  101.         writeLock.lock();  
  102.         System.out.println(Thread.currentThread().getName() + " write.");  
  103.         startTheCountdown();  
  104.         try{  
  105.             return cache.put(key, value);  
  106.         }  
  107.         finally {  
  108.             writeLock.unlock();  
  109.         }  
  110.     }  
  111.       
  112.     /** 
  113.      * A simple countdown,it will stop after about 5s.  
  114.      */  
  115.     public void startTheCountdown() {  
  116.         long currentTime = System.currentTimeMillis();  
  117.         for(;;) {  
  118.             long diff = System.currentTimeMillis() - currentTime;  
  119.             if(diff > 5000) {  
  120.                 break;  
  121.             }  
  122.         }  
  123.     }  
  124. }  

    这个例子改造自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前端,不管是移动设备的三方开发还是专业的视频剪辑技术,我都希望很自然的感兴趣了,有条件了就去狠狠的玩玩。我想我迷恋的只是高性能的计算机和互联网,哈哈。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值