程序中涉及到对一些共享资源的读和写操作,且写操作没有读操作那么频繁。在没有写操作的时候,两个线程同时读一个资源没有任何问题,所以应该允许多个线程能在同时读取共享资源。但是如果有一个线程想去写这些共享资源,就不应该再有其它线程对该资源进行读或写(译者注:也就是说:读-读能共存,读-写不能共存,写-写不能共存)。这就需要一个读/写锁来解决这个问题。

按照上面的叙述,简单的实现出一个读/写锁

public class ReadWriteLock{

  private int readers = ;

  private int writers = ;

  private int writeRequests = ;

  public synchronized void lockRead()

      throws InterruptedException{

      while(writers >  || writeRequests > ){

          wait();

      }

      readers++;

  }

  public synchronized void unlockRead(){

      readers--;

      notifyAll();

  }

  public synchronized void lockWrite()

      throws InterruptedException{

      writeRequests++;

      while(readers >  || writers > ){

          wait();

      }

      writeRequests--;

      writers++;

  }

  public synchronized void unlockWrite()

      throws InterruptedException{

      writers--;

      notifyAll();

  }

}
 

ReadWriteLock类中,读锁和写锁各有一个获取锁和释放锁的方法。

可重入的ReadWriteLock的完整实现

下面是完整的ReadWriteLock实现。为了便于代码的阅读与理解,简单对上面的代码做了重构。重构后的代码如下。

public class ReadWriteLock{

 private Map<Thread, Integer> readingThreads =

     new HashMap<Thread, Integer>();

 private int writeAccesses    = ;

 private int writeRequests    = ;

 private Thread writingThread = null;

 public synchronized void lockRead()

     throws InterruptedException{

     Thread callingThread = Thread.currentThread();

     while(! canGrantReadAccess(callingThread)){

         wait();

     }

     readingThreads.put(callingThread,

         (getReadAccessCount(callingThread) + ));

 }

 private boolean canGrantReadAccess(Thread callingThread){

     if(isWriter(callingThread)) return true;

     if(hasWriter()) return false;

     if(isReader(callingThread)) return true;

     if(hasWriteRequests()) return false;

     return true;

 }

 public synchronized void unlockRead(){

     Thread callingThread = Thread.currentThread();

     if(!isReader(callingThread)){

         throw new IllegalMonitorStateException(

             "Calling Thread does not" +

             " hold a read lock on this ReadWriteLock");

     }

     int accessCount = getReadAccessCount(callingThread);

     if(accessCount == ){

         readingThreads.remove(callingThread);

     } else {

         readingThreads.put(callingThread, (accessCount -));

     }

     notifyAll();

 }

 public synchronized void lockWrite()

     throws InterruptedException{

     writeRequests++;

     Thread callingThread = Thread.currentThread();

     while(!canGrantWriteAccess(callingThread)){

         wait();

     }

     writeRequests--;

     writeAccesses++;

     writingThread = callingThread;

 }

 public synchronized void unlockWrite()

     throws InterruptedException{

     if(!isWriter(Thread.currentThread()){

     throw new IllegalMonitorStateException(

         "Calling Thread does not" +

         " hold the write lock on this ReadWriteLock");

     }

     writeAccesses--;

     if(writeAccesses == ){

         writingThread = null;

     }

     notifyAll();

 }

 private boolean canGrantWriteAccess(Thread callingThread){

     if(isOnlyReader(callingThread)) return true;

     if(hasReaders()) return false;

     if(writingThread == null) return true;

     if(!isWriter(callingThread)) return false;

     return true;

 }

 private int getReadAccessCount(Thread callingThread){

     Integer accessCount = readingThreads.get(callingThread);

     if(accessCount == null) return ;

     return accessCount.intValue();

 }

 private boolean hasReaders(){

     return readingThreads.size() > ;

 }

 private boolean isReader(Thread callingThread){

     return readingThreads.get(callingThread) != null;

 }

 private boolean isOnlyReader(Thread callingThread){

     return readingThreads.size() ==  &&

         readingThreads.get(callingThread) != null;

 }

 private boolean hasWriter(){

     return writingThread != null;

 }

 private boolean isWriter(Thread callingThread){

     return writingThread == callingThread;

 }

 private boolean hasWriteRequests(){

     return this.writeRequests > ;

 }

}

应用:线程安全并且高并发状态下的map实现

class RWDictionary {
private final Map<String, Data> m = new TreeMap<String, Data>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock(); public Data get(String key) {
r.lock();
try { return m.get(key); }
finally { r.unlock(); }
}
public String[] allKeys() {
r.lock();
try { return m.keySet().toArray(); }
finally { r.unlock(); }
}
public Data put(String key, Data value) {
w.lock();
try { return m.put(key, value); }
finally { w.unlock(); }
}
public void clear() {
w.lock();
try { m.clear(); }
finally { w.unlock(); }
}
}

读/写锁的实现和应用(高并发状态下的map实现)的更多相关文章

  1. php高并发状态下文件的读写

    php高并发状态下文件的读写   背景 1.对于PV不高或者说并发数不是很大的应用,不用考虑这些,一般的文件操作方法完全没有问题 2.如果并发高,在我们对文件进行读写操作时,很有可能多个进程对进一文件 ...

  2. C++高并发场景下读多写少的解决方案

    C++高并发场景下读多写少的解决方案 概述 一谈到高并发的解决方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也 ...

  3. C++高并发场景下读多写少的优化方案

    概述 一谈到高并发的优化方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也能很大的影响整体性能,本文从单模块下读 ...

  4. C# 防止同时调用=========使用读写锁三行代码简单解决多线程并发的问题

    http://www.jb51.net/article/99718.htm     本文主要介绍了C#使用读写锁三行代码简单解决多线程并发写入文件时提示"文件正在由另一进程使用,因此该进程无 ...

  5. Java高并发情况下的锁机制优化

    本文主要讲并行优化的几种方式, 其结构如下: 锁优化 减少锁的持有时间 例如避免给整个方法加锁 1 public synchronized void syncMethod(){ 2 othercode ...

  6. 【高并发】高并发环境下构建缓存服务需要注意哪些问题?我和阿里P9聊了很久!

    写在前面 周末,跟阿里的一个朋友(去年晋升为P9了)聊了很久,聊的内容几乎全是技术,当然了,两个技术男聊得最多的话题当然就是技术了.从基础到架构,从算法到AI,无所不谈.中间又穿插着不少天马行空的想象 ...

  7. 关于WCF服务在高并发情况下报目标积极拒绝的异常处理

    最近弄了个wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好好的活着.于是开始查原因. 一般来说目标积极拒绝(TCP 10061)的异常主要是 ...

  8. WCF服务在高并发情况下报目标积极拒绝的异常处理 z

    http://www.cnblogs.com/kklldog/p/5037006.html wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好 ...

  9. [转]高并发访问下避免对象缓存失效引发Dogpile效应

    避免Redis/Memcached缓存失效引发Dogpile效应 Redis/Memcached高并发访问下的缓存失效时可能产生Dogpile效应(Cache Stampede效应). 推荐阅读:高并 ...

随机推荐

  1. webuploader传递参数

    实际开发过程中,比如我有个工单提交系统,提交工单的时候用webuploader上传图片,如果工单的ID是自增长类型的,那么我在上传图片的时候肯定需要关联上工单的id,这时候就需要通过webupload ...

  2. 笔记:CSS常用中文字体英文名称对照表

    * 分类排序:中文名+英文名+Unicode+Unicode 2 Windows平台新细明体 PMingLiU \65B0\7EC6\660E\4F53 新细明体细明体 MingLiU \7EC6\6 ...

  3. C#-派生类

    VS派生类 继承.派生类 class AClass : FClass 构建函数继承 public classname (string astring): base(astring){};默认不继承基类 ...

  4. 关于android4.3 bluetooth4.0的那些事儿

    马年伊始,刚刚上班的一个星期,公司里没什么事儿可做,只是听说马上可能要做蓝牙的项目.之前也做过关于软硬件通讯之类的项目:android 串口通讯,android usb 转串口通讯. 可是蓝牙这块还真 ...

  5. hdu 4974 贪心

    http://acm.hdu.edu.cn/showproblem.php?pid=4974 n个人进行选秀,有一个人做裁判,每次有两人进行对决,裁判可以选择为两人打分,可以同时加上1分,或者单独为一 ...

  6. UFOV页面 使用canvas

    canvas画八边形:cxt.beginPath();cxt.beginPath(); canvas内线条的粗细:cxt.lineWidth = '2'; 鼠标消失: css: html, body ...

  7. Android-fragment-ListView展示-v4支持包

    昨天写的这几篇博客,Android-fragment简介-fragment的简单使用,Activity-fragment-ListView展示,Android-fragment生命周期,Android ...

  8. Simple Package Tool 学习

    Simple Package Tool 学习   1.getattr内置函数 getattr(object, name[, default]) python Packages.py install - ...

  9. c#位运算小例子笔记

    关于位运算,网上有挺多好的博客介绍过,我就不多解释了 这里只记录一个小例子,是在理解位运算时候写的,帮助自己加深一下印象,做个笔记mark一下 具体场景 摇骰子游戏 1每个骰子有6个点,1-3为小,4 ...

  10. Kafka send问题

    kafka 在send之后不会立即把消息发送到broker.会把消息发到producer所在电脑内存里,后端的IOThread会扫描内存,并从中取出消息进行消费. 在调用close()或者flush( ...