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 相关文章推荐
Spring Boot两种全局配置和两种注解的操作方法
Jun 29 Java/Android
分析JVM源码之Thread.interrupt系统级别线程打断
Jun 29 Java/Android
Spring Security中用JWT退出登录时遇到的坑
Oct 16 Java/Android
Java8中Stream的一些神操作
Nov 02 Java/Android
关于@OnetoMany关系映射的排序问题,使用注解@OrderBy
Dec 06 Java/Android
深入浅出讲解Java8函数式编程
Jan 18 Java/Android
详解Flutter和Dart取消Future的三种方法
Apr 07 Java/Android
Spring Boot 实现 WebSocket
Apr 30 Java/Android
springboot读取resources下文件的方式详解
Jun 21 Java/Android
SpringBoot详解整合Redis缓存方法
Jul 15 Java/Android
阿里面试Nacos配置中心交互模型是push还是pull原理解析
Jul 23 Java/Android
HttpClient实现文件上传功能
Aug 14 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 中英文语言转换类代码
2011/08/11 PHP
PHP使用glob函数遍历目录或文件夹的方法
2014/12/16 PHP
php的优点总结 php有哪些优点
2019/07/19 PHP
Javascript 模式实例 观察者模式
2009/10/24 Javascript
浅谈JavaScript中定义变量时有无var声明的区别
2014/08/18 Javascript
鼠标悬浮停留三秒后自动显示大图js代码
2014/09/09 Javascript
JS+CSS实现带关闭按钮DIV弹出窗口的方法
2015/02/27 Javascript
avalonjs制作响应式瀑布流特效
2015/05/06 Javascript
JavaScript调用客户端Java程序的方法
2015/07/27 Javascript
Javascript实现的Map集合工具类完整实例
2015/07/31 Javascript
JS判断form内所有表单是否为空的简单实例
2016/09/09 Javascript
利用Query+bootstrap和js两种方式实现日期选择器
2017/01/10 Javascript
Vue分页组件实例代码
2017/04/17 Javascript
javascript观察者模式实现自动刷新效果
2017/09/05 Javascript
微信小程序开发之好友列表字母列表跳转对应位置
2017/09/26 Javascript
vue获取时间戳转换为日期格式代码实例
2019/04/17 Javascript
[48:32]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 LGD vs VG
2018/04/01 DOTA
Python使用urllib2获取网络资源实例讲解
2013/12/02 Python
python检测是文件还是目录的方法
2015/07/03 Python
Python的Scrapy爬虫框架简单学习笔记
2016/01/20 Python
利用pandas将numpy数组导出生成excel的实例
2018/06/14 Python
浅谈dataframe中更改列属性的方法
2018/07/10 Python
Selenium鼠标与键盘事件常用操作方法示例
2018/08/13 Python
python爬虫模拟浏览器访问-User-Agent过程解析
2019/12/28 Python
基于Django signals 信号作用及用法详解
2020/03/28 Python
Python读取二进制文件代码方法解析
2020/06/22 Python
使用Nibabel库对nii格式图像的读写操作
2020/07/01 Python
Python timeit模块原理及使用方法
2020/10/10 Python
请解释接口的显式实现有什么意义
2012/05/26 面试题
银行会计业务的个人自我评价
2013/11/02 职场文书
大学生创业计划书的格式要求
2013/12/29 职场文书
2014年开学第一课活动方案
2014/03/06 职场文书
外语专业毕业生自荐信
2014/04/14 职场文书
合作协议书格式
2014/08/19 职场文书
学习保证书怎么写
2015/02/26 职场文书
预防职务犯罪警示教育心得体会
2016/01/15 职场文书