java固定大小队列的几种实现方式详解
前言
最近团队有同学在开发中,遇到一个需求,统计最近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列表的三个操作。
- LPUSH:将元素插入头部
- LTRIM: 对列表进行裁剪,可以指定起始位置
- 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固定大小队列内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341