最近團(tuán)隊(duì)有同學(xué)在開發(fā)中血柳,遇到一個需求载庭,統(tǒng)計(jì)最近10次的異常次數(shù)辙纬,咨詢有沒有類似的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蓖谢,可以按照自己的業(yè)務(wù)需求填寫
fixedLinkedHashMap.put(UUID.randomUUID().toString(), 1);
// 讀取操作
// 獲取元素個數(shù)
long size = fixedLinkedHashMap.values().size();
// 統(tǒng)計(jì)其中的總和
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);
// 讀取元素
// 元素個數(shù)
size = evictingQueue.size();
// 統(tǒng)計(jì)其中的和
sum = evictingQueue.stream().mapToInt(value -> value).sum();
注意: 引入了目前(2021-07-12)最新的guava版本30.1.1-jre,EvictingQueue類還是標(biāo)記了@Beta纵柿。
基于Redis的list操作
示例在SpringBoot應(yīng)用中蜈抓,使用RedisTemplate。
主要基于Redis列表的三個操作昂儒。
- LPUSH:將元素插入頭部
- LTRIM: 對列表進(jìn)行裁剪沟使,可以指定起始位置
- LRANGE: 獲取列表指定范圍內(nèi)的元素
引入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);
// 對結(jié)果操作
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
總結(jié)
以上三種方式均可實(shí)現(xiàn)固定長度的list。FixedLinkedHashMap和EvictingQueue是基于內(nèi)存的拾酝,所以僅支持節(jié)點(diǎn)情況燕少。而基于Redis的list除了單節(jié)點(diǎn)情況,同樣可以在分布式情況使用蒿囤。