当前位置: 首页> 游戏> 攻略 > Java中的锁(四)利用读写锁实现高性能网页缓存

Java中的锁(四)利用读写锁实现高性能网页缓存

时间:2025/7/9 12:19:39来源:https://blog.csdn.net/dghkgjlh/article/details/141775986 浏览次数:0次

文章目录

  • 背景
  • Ehcache2源码解析-如何实现缓存网页
  • 读写锁ReentrantReadWriteLock解析
    • 读写锁的特性
    • 读写锁是如何实现的?
  • 如何将Ehcach2-web的源码迁移到Ehcach3中?/ 如何自定义Filter实现高性能网页缓存?

背景

在我们的销售页面,有一个类似日历的控件,用户可以在该控件中查找当前月份中可以买票的活动。当多个用户访问该控件时,看到的内容是一样的,没必要每个用户发起的请求再去数据库查一遍。为了提高用户体验和避免大促期间该页面给服务器带来压力,我们决定对该控件的响应进行缓存。早期使用Ehcache2的SimplePageFragmentCachingFilter实现。

由于Ehcache2不再维护,我们决定将Ehcache2迁移到Ehcache3。在将Ehcache2迁移到Ehcache3的过程中,发现Ehcache2下的ehcache-web在Ehcache3中不再支持,现有项目中仍使用ehcache-web的SimplePageCachingFilter来缓存网页,于是决定copy SimplePageCachingFilter源码并使用 Ehcache3进行改写。在这个过程中发现了此SimplePageCachingFilter的实现利用里Java的读写锁。

Ehcache2源码解析-如何实现缓存网页

  1. 缓存网页的核心逻辑在于net.sf.ehcache.constructs.web.filter.CachingFilter#buildPageInfo在这里插入图片描述
  2. blockingCache的get方法如下所示在这里插入图片描述
  3. 先拿到一个锁,该锁是net.sf.ehcache.concurrent.ReadWriteLockSync的实例在这里插入图片描述
    该类的内部有一个Java的ReentrantReadWriteLock
  4. 多线程并发时,拿到锁之后先去获取读锁,拿到之后立刻释放掉。然后去拿写锁,如果第一次拿到写锁则返回的Element对象是null,此时写锁未释放,其他并发的线程拿不到写锁就等待一定时间,此时间可配置。在这里插入图片描述
  5. 拿到写锁之后则返回到第1步,调用buildPage,最后将该对象blockingCache.put进去,写锁在这里释放在这里插入图片描述
  6. 总结一下Ehcache2的实现网页缓存的逻辑,通过配置Filter的url-pattern,在浏览器端请求该url时会对response进行缓存。具体的缓存逻辑是由Java的读写锁ReentrantReadWriteLock完成的,使用ReentrantReadWriteLock确实能解决大量并发请求一个网页内容时的性能问题

读写锁ReentrantReadWriteLock解析

读写锁的特性

直接看注释

  1. 多线程并发时,如果都去获取读锁,则不互斥;如果此时有线程拿到了写锁,再去获取读锁,则需要等待写锁释放在这里插入图片描述
  2. 获取写锁时,如果此时没有其他线程拿到读锁或写锁,则直接获取;如果其他线程此时拿着读锁或写锁,则需等到锁的释放在这里插入图片描述

读写锁是如何实现的?

在Java中的锁(二)实现自定义锁中提到了,如果想要自定义锁,需要实现Lock接口+重写AQS的方法,并在实现的Lock接口中调用AQS的模板方法,这些方法最终会调用重写的AQS方法。

  1. 看一下它的主要结构,可以看到它的实现是按照上面我们所说的思路实现在这里插入图片描述

  2. 以读锁的lock方法为例,调用AQS的模板方法acquireShared,该方法会最终调用ReentrantReadWriteLock内部类Sync中的tryAcquireShared方法
    在这里插入图片描述

如何将Ehcach2-web的源码迁移到Ehcach3中?/ 如何自定义Filter实现高性能网页缓存?

看了上面的逻辑和读写锁的特性,实现起来就很简单了

  1. 自定义一个Filter,该Filter在缓存网页时使用Ehcache3。具体做法是将网页的Response放到Ehcache中
  2. 那怎么提高 高并发下对同一个网页的访问性能呢?使用读写锁
  3. 每个需要缓存的网页url中应该都有一个标识,此标识作为缓存的key
  4. 当多个并发请求都请求同一个网页时,拿到key去cache中找,找到则直接返回
  5. 找不到则开始获取读锁,拿到读锁什么都不做,直接释放;如果拿不到读锁,则等待
  6. 释放完读锁,立刻去竞争写锁,拿到写锁之后,先判断此时cache中有没有,因为当前线程可能不是第一个拿到写锁的线程,之前的写锁可能已经将内容写入cache中了,有则直接释放写锁;cache中没有则开始将网页的Response写入到cache中,然后释放写锁
关键字:Java中的锁(四)利用读写锁实现高性能网页缓存

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: