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

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

  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. 《沉静领导》读书笔记zz

    就 像作者说的,这本书“只是一篇简单的随笔,它描绘并阐明了一种关于领导之道的思考方式,并且为把这种思考方式应用到实际行动中提供了指南.”但是,仔细想 来,倒有一点不同见解,或许,它描述的不可以叫做“领 ...

  2. 情境领导II

    情境领导理论认为,领导者的行为要与被领导者的准备程度相适应,才能取得有效的领导效果,也就是说领导风格不是一成不变的,而要根据环境及员工的变化而改变. 三大技巧分别为诊断.弹性与约定领导型态.诊断是评估 ...

  3. 2018.09.23 bzoj1076: [SCOI2008]奖励关(期望+状压dp)

    传送门 一道神奇的期望状压dp. 用f[i][j]f[i][j]f[i][j]表示目前在第i轮已选取物品状态为j,从现在到第k轮能得到的最大贡献. 如果我们从前向后推有可能会遇到不合法的情况. 所以我 ...

  4. 2018.09.19 atcoder Snuke's Coloring(思维题)

    传送门 谁能想到这道题会写这么久. 本来是一道很sb的题啊. 就是每次选一个点只会影响到周围的九个方格,随便1e9进制就可以hash了,但是我非要作死用stl写. 结果由于技术不够高超,一直调不出来. ...

  5. 2018.09.16 loj#10241. 取石子游戏 1(博弈论)

    传送门 好像是某年的初赛题啊. 有个很显然的结论. 当n" role="presentation" style="position: relative;&quo ...

  6. 2018.07.27 bzoj3064: Tyvj 1518 CPU监控(线段树)

    传送门 线段树好题. 维护区间加,区间覆盖,区间最大,区间历史最大. 这个东西在国家集训队2016论文集之<区间最值操作与历史最值问题--杭州学军中学 吉如一>中讲的已经很详细了. 简单来 ...

  7. 2018.07.22 bzoj3613: [Heoi2014]南园满地堆轻絮(逆序对结论题)

    传送门 做这道题有一个显然的结论,就是要使这个数列单调不减,就要使所有逆序对保证单调不减,也就是求出所有逆序对的最大差值,然后除以2然后就没了. 代码如下: #include<bits/stdc ...

  8. Django(3)

    https://www.cnblogs.com/yuanchenqi/articles/7429279.html

  9. mysql date_sub用法

    查询一天: select * from table where to_days(column_time) = to_days(now()); select * from table where dat ...

  10. 静态代码块和this

    /* 静态代码块.随着类的加载而执行.而且只执行一次. 作用: 用于给类进行初始化. */class StaticCode{ static int num ; static { num = 10;// ...