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 相关文章推荐
解决tk mapper 通用mapper的bug问题
Jun 16 Java/Android
springboot集成flyway自动创表的详细配置
Jun 26 Java/Android
Java中多线程下载图片并压缩能提高效率吗
Jul 01 Java/Android
使用@Value值注入及配置文件组件扫描
Jul 09 Java/Android
SpringRetry重试框架的具体使用
Jul 25 Java/Android
java调用Restful接口的三种方法
Aug 23 Java/Android
Java 在线考试云平台的实现
Nov 23 Java/Android
Java中try catch处理异常示例
Dec 06 Java/Android
Java后端 Dubbo retries 超时重试机制的解决方案
Apr 14 Java/Android
Java 多态分析
Apr 26 Java/Android
SpringCloud中分析讲解Feign组件添加请求头有哪些坑梳理
Jun 21 Java/Android
springboot创建的web项目整合Quartz框架的项目实践
Jun 21 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 常用函数库和一些实用小技巧
2009/01/01 PHP
Ha0k 0.3 PHP 网页木马修改版
2009/10/11 PHP
mayfish 数据入库验证代码
2010/04/30 PHP
PHP读取网页文件内容的实现代码(fopen,curl等)
2011/06/23 PHP
CodeIgniter框架验证码类库文件与用法示例
2017/03/18 PHP
yii框架无限极分类的实现方法
2017/04/08 PHP
PHP编程实现脚本异步执行的方法
2017/08/09 PHP
javascript让setInteval里的函数参数中的this指向特定的对象
2010/01/31 Javascript
jquery animate图片模向滑动示例代码
2011/01/26 Javascript
JQuery之focus函数使用介绍
2013/08/20 Javascript
Javascript实现获取窗口的大小和位置代码分享
2014/12/04 Javascript
jQuery制作拼图小游戏
2015/01/12 Javascript
PHPMyAdmin导入时提示文件大小超出PHP限制的解决方法
2015/03/30 Javascript
JS根据key值获取URL中的参数值及把URL的参数转换成json对象
2015/08/26 Javascript
JavaScript优化专题之Loading and Execution加载和运行
2016/01/20 Javascript
浅析$.getJSON异步请求和同步请求
2016/06/06 Javascript
underscore之Chaining_动力节点Java学院整理
2017/07/10 Javascript
用JavaScript做简易的购物车的代码示例
2017/10/20 Javascript
vue19 组建 Vue.extend component、组件模版、动态组件 的实例代码
2019/04/04 Javascript
js变量值传到php过程详解 将php解析成数据
2019/06/26 Javascript
javascript实现点亮灯泡特效示例
2019/10/15 Javascript
JS校验与最终登陆界面功能完整示例
2020/01/13 Javascript
JS使用setInterval计时器实现挑战10秒
2020/11/08 Javascript
[01:12:44]VG vs Mineski Supermajor 败者组 BO3 第二场 6.6
2018/06/07 DOTA
[01:51]2018年度CS GO最具人气外援-完美盛典
2018/12/16 DOTA
Python安装Imaging报错:The _imaging C module is not installed问题解决方法
2014/08/22 Python
python中itertools模块zip_longest函数详解
2018/06/12 Python
PyQt5实现暗黑风格的计时器
2019/07/29 Python
Python实现TCP探测目标服务路由轨迹的原理与方法详解
2019/09/04 Python
在Mac中PyCharm配置python Anaconda环境过程图解
2020/03/11 Python
深入剖析webstorage[html5的本地数据处理]
2016/07/11 HTML / CSS
白色公司:The White Company
2017/10/11 全球购物
《都江堰》教学反思
2014/02/07 职场文书
司机个人年终总结
2015/03/03 职场文书
遇事可以测出您的见识与格局
2019/09/16 职场文书
使用这 6个Vue加载动画库来减少我们网站的跳出率
2021/05/18 Vue.js