java固定大小队列的几种实现方式详解


Posted in Java/Android onJuly 15, 2021

前言

最近团队有同学在开发中,遇到一个需求,统计最近10次的异常次数,咨询有没有类似的list。针对这个问题,记录一下几种处理方式。

基于Hutool中的FixedLinkedHashMap

引入maven依赖

<dependency>
   <groupId>cn.hutool</groupId>
   <artifactId>hutool-all</artifactId>
   <version>5.4.0</version>
</dependency>

使用示例

// 初始化时指定大小
private final FixedLinkedHashMap<String, Integer> fixedLinkedHashMap = new FixedLinkedHashMap<>(LIST_SIZE);

// 其余写入和读取操作同LinkedHashMap类似
// 对于key,可以按照自己的业务需求填写
fixedLinkedHashMap.put(UUID.randomUUID().toString(), 1);

// 读取操作
// 获取元素个数
long size = fixedLinkedHashMap.values().size();
// 统计其中的总和
int sum = fixedLinkedHashMap.values().stream().mapToInt(value -> value).sum();

基于Guava的EvictingQueue

引入maven依赖

<dependency>
   <groupId>com.google.guava</groupId>
   <artifactId>guava</artifactId>
   <version>30.1.1-jre</version>
</dependency>

使用示例

// 初始化时指定大小
private final EvictingQueue<Integer> evictingQueue = EvictingQueue.create(LIST_SIZE);

// 添加元素
evictingQueue.add(MOCK_EXCEPTION_COUNT);

// 读取元素
// 元素个数
size = evictingQueue.size();
// 统计其中的和
sum = evictingQueue.stream().mapToInt(value -> value).sum();

注意: 引入了目前(2021-07-12)最新的guava版本30.1.1-jre,EvictingQueue类还是标记了@Beta。

基于Redis的list操作

示例在SpringBoot应用中,使用RedisTemplate。

主要基于Redis列表的三个操作。

  1. LPUSH:将元素插入头部
  2. LTRIM: 对列表进行裁剪,可以指定起始位置
  3. LRANGE: 获取列表指定范围内的元素

引入maven依赖

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

使用示例

// 初始化RedisTemplate
@Resource
private RedisTemplate<String, Integer> redisTemplate;


ListOperations<String, Integer> stringIntegerListOperations = redisTemplate.opsForList();
// LPUSH操作
stringIntegerListOperations.leftPush(REDIS_LIST_KEY, MOCK_EXCEPTION_COUNT);
// LTRIM
stringIntegerListOperations.trim(REDIS_LIST_KEY, 0, LIST_SIZE - 1);
// LRANGE操作
List<Integer> range = stringIntegerListOperations.range(REDIS_LIST_KEY, 0, LIST_SIZE - 1);

// 对结果操作
size = range.size();
sum = range.stream().mapToInt(value -> value).sum();

完整示例

@Service
@Slf4j
public class FixedListScheduler {

  private static final int LIST_SIZE = 10;

  private static final int MOCK_EXCEPTION_COUNT = 1;

  private static final String REDIS_LIST_KEY = "redis_fixed_list";

  private final FixedLinkedHashMap<String, Integer> fixedLinkedHashMap = new FixedLinkedHashMap<>(LIST_SIZE);

  private final EvictingQueue<Integer> evictingQueue = EvictingQueue.create(LIST_SIZE);

  @Resource
  private RedisTemplate<String, Integer> redisTemplate;

  @Scheduled(cron = "*/1 * * * * ?")
  public void schedule() {
    fixedLinkedHashMap.put(UUID.randomUUID().toString(), MOCK_EXCEPTION_COUNT);

    long size = fixedLinkedHashMap.values().size();
    int sum = fixedLinkedHashMap.values().stream().mapToInt(value -> value).sum();

    log.info("fixedLinkedHashMap size:{}, sum:{}", size, sum);
    evictingQueue.add(MOCK_EXCEPTION_COUNT);
    size = evictingQueue.size();
    sum = evictingQueue.stream().mapToInt(value -> value).sum();
    log.info("evictingQueue size:{}, sum:{}", size, sum);

    ListOperations<String, Integer> stringIntegerListOperations = redisTemplate.opsForList();
    stringIntegerListOperations.leftPush(REDIS_LIST_KEY, MOCK_EXCEPTION_COUNT);
    stringIntegerListOperations.trim(REDIS_LIST_KEY, 0, LIST_SIZE - 1);

    List<Integer> range = stringIntegerListOperations.range(REDIS_LIST_KEY, 0, LIST_SIZE - 1);
    if (!CollectionUtils.isEmpty(range)) {
      sum = range.stream().mapToInt(value -> value).sum();
      log.info("redis FixedList size:{}, sum:{}", range.size(), sum);
    }
  }
}

程序启动一段时间后的日志,可以看到是满足要求的。

2021-07-12 18:35:29.006  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : evictingQueue size:10, sum:10
2021-07-12 18:35:29.009  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : redis FixedList size:10, sum:10
2021-07-12 18:35:30.002  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : fixedLinkedHashMap size:10, sum:10
2021-07-12 18:35:30.002  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : evictingQueue size:10, sum:10
2021-07-12 18:35:30.005  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : redis FixedList size:10, sum:10
2021-07-12 18:35:31.005  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : fixedLinkedHashMap size:10, sum:10
2021-07-12 18:35:31.005  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : evictingQueue size:10, sum:10
2021-07-12 18:35:31.008  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : redis FixedList size:10, sum:10
2021-07-12 18:35:32.005  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : fixedLinkedHashMap size:10, sum:10
2021-07-12 18:35:32.005  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : evictingQueue size:10, sum:10
2021-07-12 18:35:32.009  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : redis FixedList size:10, sum:10
2021-07-12 18:35:33.002  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : fixedLinkedHashMap size:10, sum:10
2021-07-12 18:35:33.002  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : evictingQueue size:10, sum:10
2021-07-12 18:35:33.005  INFO 8622 --- [pool-2-thread-1] com.yichao.myblogs.FixedListScheduler    : redis FixedList size:10, sum:10

总结

以上三种方式均可实现固定长度的list。FixedLinkedHashMap和EvictingQueue是基于内存的,所以仅支持节点情况。而基于Redis的list除了单节点情况,同样可以在分布式情况使用。

到此这篇关于java固定大小队列的文章就介绍到这了,更多相关java固定大小队列内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Java/Android 相关文章推荐
浅谈Java实现分布式事务的三种方案
Jun 11 Java/Android
Java 数组内置函数toArray详解
Jun 28 Java/Android
Java中多线程下载图片并压缩能提高效率吗
Jul 01 Java/Android
Java使用httpRequest+Jsoup爬取红蓝球号码
Jul 02 Java/Android
JavaWeb 入门篇(3)ServletContext 详解 具体应用
Jul 16 Java/Android
Spring Boot 排除某个类加载注入IOC的操作
Aug 02 Java/Android
Java数据开发辅助工具Docker与普通程序使用方法
Sep 15 Java/Android
IDEA2021.2配置docker如何将springboot项目打成镜像一键发布部署
Sep 25 Java/Android
关于Spring配置文件加载方式变化引发的异常详解
Jan 18 Java/Android
SpringBoot整合Minio文件存储
Apr 03 Java/Android
Flutter集成高德地图并添加自定义Maker的实践
Apr 07 Java/Android
mybatis 获取更新记录的id
May 20 Java/Android
gateway网关接口请求的校验方式
spring cloud gateway中如何读取请求参数
Spring Cloud Gateway去掉url前缀
Jul 15 #Java/Android
小程序与后端Java接口交互实现HelloWorld入门
Java生成读取条形码和二维码的简单示例
Jul 09 #Java/Android
详细了解java监听器和过滤器
Jul 09 #Java/Android
Java使用jmeter进行压力测试
You might like
php过滤敏感词的示例
2014/03/31 PHP
php常用字符串处理函数实例分析
2014/11/22 PHP
载入进度条 效果
2006/07/08 Javascript
JS定时器实例
2013/04/17 Javascript
深入document.write()与HTML4.01的非成对标签的详解
2013/05/08 Javascript
javascript-简单的日历实现及Date对象语法介绍(附图)
2013/05/30 Javascript
Javascript核心读书有感之词法结构
2015/02/01 Javascript
浅谈javascript中的闭包
2015/05/13 Javascript
BootStrap Table后台分页时前台删除最后一页所有数据refresh刷新后无数据问题
2016/12/28 Javascript
微信JSAPI支付操作需要注意的细节
2017/01/10 Javascript
jquery实现一个全局计时器(商城可用)
2017/06/30 jQuery
vue.js中created方法作用
2018/03/30 Javascript
vue实现滑动到底部加载更多效果
2020/10/27 Javascript
vue-router为激活的路由设置样式操作
2020/07/18 Javascript
vue中echarts图表大小适应窗口大小且不需要刷新案例
2020/07/19 Javascript
vue之封装多个组件调用同一接口的案例
2020/08/11 Javascript
jQuery实现动态加载瀑布流
2020/09/01 jQuery
Vue3为什么这么快
2020/09/23 Javascript
[04:03]辉夜杯主赛事 12月25日RECAP精彩回顾
2015/12/26 DOTA
[01:03:54]Liquid vs IG 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Python多线程实例教程
2014/09/06 Python
轻松掌握python设计模式之访问者模式
2016/11/18 Python
详解python基础之while循环及if判断
2017/08/24 Python
使用python生成目录树
2018/03/29 Python
Python实现模拟浏览器请求及会话保持操作示例
2018/07/30 Python
selenium + python 获取table数据的示例讲解
2018/10/13 Python
python 2.7 检测一个网页是否能正常访问的方法
2018/12/26 Python
浅谈Python大神都是这样处理XML文件的
2019/05/31 Python
Python中bisect的用法及示例详解
2020/07/20 Python
深入浅析Python代码规范性检测
2020/07/31 Python
应届生学校辅导员求职信
2013/11/07 职场文书
社区优秀志愿者先进事迹
2014/05/09 职场文书
投标授权委托书范文
2014/08/02 职场文书
工程部主管岗位职责
2015/02/12 职场文书
运动会通讯稿300字
2015/07/20 职场文书
班主任远程培训研修日志
2015/11/13 职场文书