java缓存怎么实现,java实现一个本地缓存

  java缓存怎么实现,java实现一个本地缓存

  缓存,我相信大家都很熟悉。在一个项目中,缓存肯定是必不可少的。市面上有很多缓存工具,比如Redis,Guava Cache或者EHcache。

  如何解决写爬虫IP受阻的问题?立即使用。

  这些工具我想大家都很熟悉了,今天就不多说了。先说一下如何实现本地缓存。参考以上工具,要实现更好的本地缓存,平头哥认为要从以下三个方面入手。

  1、存储集合的选择

  要实现本地缓存,存储容器必须是键/值形式的数据结构。在Java中,它也是我们常用的地图集合。HashMap有几种,Hashtable和ConcurrentHashMap供我们选择。如果不考虑高并发下的数据安全,我们可以选择HashMap。如果考虑高并发下的数据安全,可以选择Hashtable和ConcurrentHashMap中的一个。但是我们更喜欢ConcurrentHashMap,因为ConcurrentHashMap的性能比Hashtable好。

  2、过期缓存处理

  因为缓存是直接存储在内存中的,如果我们不处理过期的缓存,内存就会被大量无效的缓存占用,这不是我们想要的,所以我们需要清理这些无效的缓存。过期缓存处理可以参考Redis的策略来实现,该策略采用定期删懒和消除懒的策略。

  定期删除策略

  定期删除策略是每隔一段时间检测一次过期的缓存并将其删除。这种策略的优点是可以确保删除所有过期的缓存。同时也有不利之处。过期的缓存可能没有及时删除,这和我们设置的定时频率有关系。还有一个缺点就是,如果缓存的数据很多,每次测试也会给杯赛带来很大的压力。

  懒惰淘汰策略

  懒惰策略是在使用缓存时判断缓存是否过期,如果过期则删除,返回null。这种策略的好处是,只有搜索的时候,才能判断是否过期,对杯子影响很大。同时,这种策略有致命的缺点。当存储了大量缓存时,这些缓存未被使用且过期,都会成为无效缓存。这些无效的缓存会占用你大量的内存空间,最终导致服务器内存溢出。

  我们简单了解一下Redis的两种逾期缓存处理策略,每种策略各有利弊。所以在使用过程中可以将两种策略结合起来,结合效果还是很理想的。

  3、缓存淘汰策略

  缓存过时不同于过期缓存处理。缓存过时意味着当我们的缓存数量达到我们指定的数量时,毕竟我们的内存不是无限的。如果需要继续添加缓存,就需要按照一定的策略让现有缓存中的一些缓存退役,为新添加的缓存腾出空间。让我们了解几种常见的缓存失效策略。

  先进先出策略

  当缓存空间不够时,先进入缓存的数据会先被清除,为新数据腾出空间。这个策略主要比较缓存元素的创建时间。在一些对数据有效性要求较高的场景下,可以考虑这种策略,首先保证最新数据的可用性。

  最少使用策略

  不管是否过期,根据元素被使用的次数,清除使用次数少的元素释放的空间。该策略主要比较元素的命中数,在保证高频数据有效性的场景下可以选择。

  最近最少使用策略

  不管是否过期,根据最后一次使用元素的时间戳,清除时间戳最远的元素空闲空间。这个策略主要比较get最后一次使用缓存的时间。更适用于热数据场景,首先保证热数据的有效性。

  随机淘汰策略

  无论缓存是否过期,它都将随机失效。如果对缓存数据没有要求,可以考虑这个策略。

  不淘汰策略

  当缓存达到指定值时,不会有缓存被停用,但不会添加新的缓存,并且在停用之前不会添加缓存。

  上面是实现本地缓存需要考虑的三个点,看完我们应该知该如何实现一个本地缓存了,不妨我们一起来实现一个本地缓存。

  实现本地缓存

  在该演示中,我们采用实现队列作为存储集合,这样即使在高并发的情况下,我们也能够保证缓存的安全。过期缓存处理在这里我只使用了定时删除策略,并没有使用定时删除懒惰淘汰策略,你可以自己动手尝试一下使用这两种策略进行过期缓存处理。在缓存淘汰方面,我在这里采用了最少使用策略。好了,技术选型都知道了,我们一起来看看代码实现。

  缓存对象类

  公共类缓存实现ComparableCache{

  //键

  私有对象密钥;

  //缓存值

  私有对象值;

  //最后一次访问时间

  私有长访问时间;

  //创建时间

  私有长写时间;

  //存活时间

  私有长过期时间

  //命中次数

  私有整数点击次数;

  .getter/setter().添加缓存

  /**

  * 添加缓存

  *

  * @param key

  * @param值

  */

  公共无效卖出(K密钥、五值、长期过期){

  checkNotNull(key);

  checkNotNull(值);

  //当缓存存在时,更新缓存

  if(并发hashmap。包含键(key)){

  cache cache=并发hashmap。get(键);

  缓存。sethitcount(缓存。gethitcount()1);

  缓存。设置写入时间(系统。当前时间毫秒());

  缓存。setaccesstime(系统。当前时间毫秒());

  cache.setExpireTime(过期);

  cache.setValue(值);

  返回;

  }

  //已经达到最大缓存

  if (isFull()) {

  object kicked key=get kicked key();

  如果(kickedKey!=null){

  //移除最少使用的缓存

  并发哈希表。移除(踢键);

  }否则{

  返回;

  }

  }

  Cache Cache=new Cache();

  缓存。setkey(键);

  cache.setValue(值);

  缓存。设置写入时间(系统。当前时间毫秒());

  缓存。setaccesstime(系统。当前时间毫秒());

  缓存。sethitcount(1);

  cache.setExpireTime(过期);

  concurrentHashMap.put(key,cache);

  }获取缓存

  /**

  * 获取缓存

  *

  * @param key

  * @返回

  */

  公共对象获取(K密钥){

  checkNotNull(key);

  if (concurrentHashMap.isEmpty())返回空

  如果(!并发哈希表。包含密钥(密钥))返回空

  cache cache=并发hashmap。get(键);

  if (cache==null)返回null

  缓存。sethitcount(缓存。gethitcount()1);

  缓存。setaccesstime(系统。当前时间毫秒());

  返回缓存。getvalue();

  }获取最少使用的缓存

  /**

  * 获取最少使用的缓存

  * @返回

  */

  私有对象getKickedKey() {

  缓存最小值=集合。min(并发哈希表。values());

  返回量滴getkey();

  }过期缓存检测方法

  /**

  * 处理过期缓存

  */

  类超时定时器线程实现可运行{

  公共无效运行(){

  while (true) {

  尝试{

  时间单位10.25秒。睡眠(60);

  过期缓存();

  } catch(异常e) {

  e。printstacktrace();

  }

  }

  }

  /**

  * 创建多久后,缓存失效

  *

  * @抛出异常

  */

  私有void expireCache()引发异常{

  System.out.println(检测缓存是否过期缓存);

  for(Object key:concurrent hashmap。密钥集()){

  cache cache=并发hashmap。get(键);

  长时间超时=时间单位。纳秒。到秒(System.nanoTime()

  缓存。获取写时间());

  如果(缓存。getexpiretime()超时时间){

  继续;

  }

  System.out.println(清除过期缓存: 键);

  //清除过期缓存

  并发哈希表。移除(键);

  }

  }

  }以上就是实现爪哇本地缓存,该从这几点开始的详细内容,更多请关注我们其它相关文章!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: