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

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

目录

  • 前言
  • 基于Hutool中的FixedLinkedHashMap
  • 基于Guava的EvictingQueue
  • 基于Redis的list操作
  • 总结

前言

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

基于Hutool中的FixedLinkedHashMap

引入maven依赖

1

2

3

4

5

<dependency>

   <groupId>cn.hutool</groupId>

   <artifactId>hutool-all</artifactId>

   <version>5.4.0</version>

</dependency>

使用示例

1

2

3

4

5

6

7

8

9

10

11

12

// 初始化时指定大小

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依赖

1

2

3

4

5

<dependency>

   <groupId>com.google.guava</groupId>

   <artifactId>guava</artifactId>

   <version>30.1.1-jre</version>

</dependency>

使用示例

1

2

3

4

5

6

7

8

9

10

11

// 初始化时指定大小

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依赖

1

2

3

4

<dependency>

   <groupId>org.springframework.boot</groupId>

   <artifactId>spring-boot-starter-data-redis</artifactId>

</dependency>

使用示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

// 初始化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();

完整示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

@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除了单节点情况,同样可以在分布式情况使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值