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

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

  1. public class ReadWriteLock{
  2.  
  3. private int readers = ;
  4.  
  5. private int writers = ;
  6.  
  7. private int writeRequests = ;
  8.  
  9. public synchronized void lockRead()
  10.  
  11. throws InterruptedException{
  12.  
  13. while(writers > || writeRequests > ){
  14.  
  15. wait();
  16.  
  17. }
  18.  
  19. readers++;
  20.  
  21. }
  22.  
  23. public synchronized void unlockRead(){
  24.  
  25. readers--;
  26.  
  27. notifyAll();
  28.  
  29. }
  30.  
  31. public synchronized void lockWrite()
  32.  
  33. throws InterruptedException{
  34.  
  35. writeRequests++;
  36.  
  37. while(readers > || writers > ){
  38.  
  39. wait();
  40.  
  41. }
  42.  
  43. writeRequests--;
  44.  
  45. writers++;
  46.  
  47. }
  48.  
  49. public synchronized void unlockWrite()
  50.  
  51. throws InterruptedException{
  52.  
  53. writers--;
  54.  
  55. notifyAll();
  56.  
  57. }
  58.  
  59. }
 

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

可重入的ReadWriteLock的完整实现

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

  1. public class ReadWriteLock{
  2.  
  3. private Map<Thread, Integer> readingThreads =
  4.  
  5. new HashMap<Thread, Integer>();
  6.  
  7. private int writeAccesses = ;
  8.  
  9. private int writeRequests = ;
  10.  
  11. private Thread writingThread = null;
  12.  
  13. public synchronized void lockRead()
  14.  
  15. throws InterruptedException{
  16.  
  17. Thread callingThread = Thread.currentThread();
  18.  
  19. while(! canGrantReadAccess(callingThread)){
  20.  
  21. wait();
  22.  
  23. }
  24.  
  25. readingThreads.put(callingThread,
  26.  
  27. (getReadAccessCount(callingThread) + ));
  28.  
  29. }
  30.  
  31. private boolean canGrantReadAccess(Thread callingThread){
  32.  
  33. if(isWriter(callingThread)) return true;
  34.  
  35. if(hasWriter()) return false;
  36.  
  37. if(isReader(callingThread)) return true;
  38.  
  39. if(hasWriteRequests()) return false;
  40.  
  41. return true;
  42.  
  43. }
  44.  
  45. public synchronized void unlockRead(){
  46.  
  47. Thread callingThread = Thread.currentThread();
  48.  
  49. if(!isReader(callingThread)){
  50.  
  51. throw new IllegalMonitorStateException(
  52.  
  53. "Calling Thread does not" +
  54.  
  55. " hold a read lock on this ReadWriteLock");
  56.  
  57. }
  58.  
  59. int accessCount = getReadAccessCount(callingThread);
  60.  
  61. if(accessCount == ){
  62.  
  63. readingThreads.remove(callingThread);
  64.  
  65. } else {
  66.  
  67. readingThreads.put(callingThread, (accessCount -));
  68.  
  69. }
  70.  
  71. notifyAll();
  72.  
  73. }
  74.  
  75. public synchronized void lockWrite()
  76.  
  77. throws InterruptedException{
  78.  
  79. writeRequests++;
  80.  
  81. Thread callingThread = Thread.currentThread();
  82.  
  83. while(!canGrantWriteAccess(callingThread)){
  84.  
  85. wait();
  86.  
  87. }
  88.  
  89. writeRequests--;
  90.  
  91. writeAccesses++;
  92.  
  93. writingThread = callingThread;
  94.  
  95. }
  96.  
  97. public synchronized void unlockWrite()
  98.  
  99. throws InterruptedException{
  100.  
  101. if(!isWriter(Thread.currentThread()){
  102.  
  103. throw new IllegalMonitorStateException(
  104.  
  105. "Calling Thread does not" +
  106.  
  107. " hold the write lock on this ReadWriteLock");
  108.  
  109. }
  110.  
  111. writeAccesses--;
  112.  
  113. if(writeAccesses == ){
  114.  
  115. writingThread = null;
  116.  
  117. }
  118.  
  119. notifyAll();
  120.  
  121. }
  122.  
  123. private boolean canGrantWriteAccess(Thread callingThread){
  124.  
  125. if(isOnlyReader(callingThread)) return true;
  126.  
  127. if(hasReaders()) return false;
  128.  
  129. if(writingThread == null) return true;
  130.  
  131. if(!isWriter(callingThread)) return false;
  132.  
  133. return true;
  134.  
  135. }
  136.  
  137. private int getReadAccessCount(Thread callingThread){
  138.  
  139. Integer accessCount = readingThreads.get(callingThread);
  140.  
  141. if(accessCount == null) return ;
  142.  
  143. return accessCount.intValue();
  144.  
  145. }
  146.  
  147. private boolean hasReaders(){
  148.  
  149. return readingThreads.size() > ;
  150.  
  151. }
  152.  
  153. private boolean isReader(Thread callingThread){
  154.  
  155. return readingThreads.get(callingThread) != null;
  156.  
  157. }
  158.  
  159. private boolean isOnlyReader(Thread callingThread){
  160.  
  161. return readingThreads.size() == &&
  162.  
  163. readingThreads.get(callingThread) != null;
  164.  
  165. }
  166.  
  167. private boolean hasWriter(){
  168.  
  169. return writingThread != null;
  170.  
  171. }
  172.  
  173. private boolean isWriter(Thread callingThread){
  174.  
  175. return writingThread == callingThread;
  176.  
  177. }
  178.  
  179. private boolean hasWriteRequests(){
  180.  
  181. return this.writeRequests > ;
  182.  
  183. }
  184.  
  185. }

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

  1. class RWDictionary {
  2. private final Map<String, Data> m = new TreeMap<String, Data>();
  3. private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
  4. private final Lock r = rwl.readLock();
  5. private final Lock w = rwl.writeLock();
  6.  
  7. public Data get(String key) {
  8. r.lock();
  9. try { return m.get(key); }
  10. finally { r.unlock(); }
  11. }
  12. public String[] allKeys() {
  13. r.lock();
  14. try { return m.keySet().toArray(); }
  15. finally { r.unlock(); }
  16. }
  17. public Data put(String key, Data value) {
  18. w.lock();
  19. try { return m.put(key, value); }
  20. finally { w.unlock(); }
  21. }
  22. public void clear() {
  23. w.lock();
  24. try { m.clear(); }
  25. finally { w.unlock(); }
  26. }
  27. }

读/写锁的实现和应用(高并发状态下的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. 【Web】网站主如何更改网页标签的图标(favicon.ico)

    修改web项目的favicon图标,方式有两种:全局方式和局部方式 全局方式: 进入服务器\webapps\ROOT,然后用自己的favicon.ico替换服务器自带的favicon.ico图片 局部 ...

  2. jsoup Java HTML解析器:使用选择器语法来查找元素

    jsoup Java HTML解析器:使用选择器语法来查找元素 使用选择器语法来查找元素 问题 你想使用类似于CSS或jQuery的语法来查找和操作元素. 方法 可以使用Element.select( ...

  3. org.eclipse.ui.PartInitException: Unable to open editor, unknown editor ID: org.xmen.ui.text.XMLTextEditor

    无法打开struts模式的编译xml的编译器,然后打开.project文件,编辑最后一行,找到<natures>结点,增加一条<nature>com.genuitec.ecli ...

  4. UVaLive 6525 Attacking rooks (二分图最大匹配)

    题意:给定一个 n * n的图,X是卒, . 是空位置,让你放尽量多的车,使得他们不互相攻击. 析:把每行连续的 . 看成X集体的一个点,同理也是这样,然后求一个最大匹配即可. 代码如下: #prag ...

  5. BZOJ 1005 [HNOI2008]明明的烦恼 (Prufer编码 + 组合数学 + 高精度)

    1005: [HNOI2008]明明的烦恼 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 5786  Solved: 2263[Submit][Stat ...

  6. HDU 3177 Crixalis's Equipment (贪心,差值)

    题意:判断 n 件物品是否可以搬进洞里,每件物品有实际体积A和移动时的额外体积 B . 析:第一反应就是贪心,一想是不是按B从大到小,然后一想,不对,比如体积是20,第一个 是A=11, B=19.第 ...

  7. python 判断是否是空行或注释行

    #coding:utf-8 '''''cdays-4-exercise-6.py 文件基本操作 @note: 文件读取写入, 列表排序, 字符串操作 @see: 字符串各方法可参考hekp(str)或 ...

  8. obj-c的优缺点

    优点: 1) Cateogies : 类别 2) Posing : 扮演 3) 动态识别 : 编译时与运行时动态识别类型 4) 指标计算 : 指针计算 指针的 +- * / 5) 弹性信息传递 : 某 ...

  9. [转] ubuntu安装Sublime Text 3并使用SublimeClang插件

    原文地址:https://blog.csdn.net/cywosp/article/details/32721011 3. 安装强大的SublimeClang插件 SublimeClang是Subli ...

  10. hdu1251 && hud 1247 (字典树)

    hdu1251 题目 这道题,主要是在主函数的输入输出上犹豫了. #include<stdio.h> #include<cstring> #include<iostrea ...