实现一个带过期时间的LRU Cache-阿里面试正好问到

要求如下

该cache有一个固定大小size,如果元素超过size,则需要做元素剔除动作。

剔除的优先级为,有设置优先级的元素需要按照最早过期顺序进行剔除,如果不存在设置优先级的元素,则从总元素中通过LRU剔除一个。

对元素的任何修改动作都需要重置元素的过期时间,例如一个元素已经设置了过期时间,对其进行不带过期时间的add,则会将其过期时间抹除,会变成是一个不带过期时间的元素,除非重新执行待过期时间的add动作。

只要求实现add和get方法。

public static class LRUWithTimeOut {
    private int size = Integer.MAX_VALUE;
    private LinkedHashMap<String, String> map;
    private ConcurrentHashMap<String, TimeoutInfo> timeoutMap = new ConcurrentHashMap<>();
    private PriorityQueue<String> queue = new PriorityQueue<>(new ItemWithTimeout(timeoutMap));


    public LRUWithTimeOut(int maxSize) {
      if (maxSize > 0) {
        this.size = maxSize;
      }
      map = new LinkedHashMap<String, String>(size) {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
          return this.size() > size;
        }
      };
    }

    /**
     * @param key
     * @param value
     */
    public synchronized void add(String key, String value) {
      add(key, value, null);
    }

    public synchronized void add(String key, String value, Long expireTime) {
      if (StringUtils.isEmpty(key)) {
        throw new RuntimeException("key is empty");
      }
      if (expireTime != null && expireTime < 0) {
        throw new RuntimeException("expireTime can not be negative");
      }
      queue.remove(key);
      timeoutMap.remove(key);
      map.remove(key);
      if (map.size() == size) {
        String item = queue.poll();
        if (item != null) {
          timeoutMap.remove(item);
          map.remove(item);
        }
      }
      map.put(key, value);
      if (expireTime != null && expireTime > 0) {
        timeoutMap.put(key, new TimeoutInfo(System.currentTimeMillis(), expireTime));
        queue.add(key);
      }
    }

    public synchronized String get(String key) {
      TimeoutInfo timeoutInfo = timeoutMap.get(key);
      if (!map.containsKey(key)) {
        return null;
      }
      if (timeoutInfo == null) {
        return map.get(key);
      } else {
        if (timeoutInfo.getTimeoutMills() + timeoutInfo.getCurrentTimeMills() >= System.currentTimeMillis()) {
          queue.remove(key);
          timeoutMap.remove(key);
          map.remove(key);
          return null;
        }
        queue.remove(key);
        timeoutMap.remove(key);
        timeoutInfo.setCurrentTimeMills(System.currentTimeMillis());
        timeoutMap.put(key, timeoutInfo);
        queue.add(key);
        return map.get(key);
      }
    }

    @AllArgsConstructor
    private class ItemWithTimeout implements Comparator<String> {

      private Map<String, TimeoutInfo> timeoutMap = new HashMap<>();

      @Override
      public int compare(String o1, String o2) {
        return timeoutMap.get(o1).expiredTimeMills() - timeoutMap.get(o2).expiredTimeMills() > 0 ? 1 : -1;
      }
    }

    @Data
    private class TimeoutInfo {
      private long currentTimeMills;
      private long timeoutMills;

      public TimeoutInfo(long currentTimeMills, long timeoutMills) {
        this.currentTimeMills = currentTimeMills;
        this.timeoutMills = timeoutMills;
      }

      private TimeoutInfo() {

      }

      public long expiredTimeMills() {
        return this.currentTimeMills + this.timeoutMills;
      }
    }

  }

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慢一点,细一点

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值