0
点赞
收藏
分享

微信扫一扫

根据优先级 + LRU 缓存数据



文章目录

  • 前言
  • 一、优先级队列
  • PriorityQueue 简介
  • 二、优先级+LRU
  • 总结


前言

在项目中遇到了,需要根据 优先级 + LRU 缓存数据;

LRU 优先考虑采用hutool ,然后自己附加搞上 一个优先级就行了

一、优先级队列

PriorityQueue 简介

  1. PriorityQueue是基于优先级堆的无界队列。
  2. PriorityQueue的作用是保证每次取出的都是队列中权值最小的元素,也可以说是最高优先级的元素。
  3. PriorityQueue的元素排序是按照自然排序来进行排序的,在创建时可以给他添加一个给元素排序的比较器。

offer():添加元素到队列中,如果队列已满,则返回false。
poll():检索并删除队列中的最小元素,如果队列为空,则返回null。
remove():检索并删除队列中的最小元素,如果队列为空,则返回null。
add():添加元素到队列中。
peek():检索但不删除队列中的最小元素,如果队列为空,则返回null。
size():返回队列中的元素数目。
iterator():返回一个迭代器,该迭代器可以按排序的顺序遍历队列中的元素。

二、优先级+LRU

由于PriorityQueue 是无界队列,所以需要保证队列长度不超过最大值由于每次获取的都是优先级最高的元素,所以采用倒叙,也就是优先级高的在最后 ,数值越小越靠后,优先级越高采用读写锁,控制并发

import cn.hutool.cache.CacheListener;
import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.LRUCache;
import cn.hutool.json.JSONUtil;
import java.util.AbstractMap;
import java.util.Comparator;
import java.util.Map.Entry;
import java.util.PriorityQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.springframework.util.ObjectUtils;

/**
 * 根据优先级 + LRU 缓存数据
 *
 * @author fulin
 * @since 2023/11/15 16:11
 */
public class PriorityLRUCache {

  private PriorityLRUCache() {
  }

  // 存储最大值
  private static int maxSize = 3;

  // 缓存时间 单位ms
  private static int time = 90000;

  public static void setMaxSize(int maxSize) {
    PriorityLRUCache.maxSize = maxSize;
  }

  public static void setTime(int time) {
    PriorityLRUCache.time = time;
  }

  // lru 存储 单位ms
  private static final LRUCache<Object, Object> lruCache = CacheUtil.newLRUCache(maxSize * 2,
      time);

  // 优先级队列,存储键值对,并根据使用频率排序 降序,优先级高的在最后
  // 数值越小越靠后,优先级越高
  private static final PriorityQueue<Entry<Object, Integer>> priorityQueue = new PriorityQueue<>(
      maxSize, Comparator.comparingInt(o -> -(o.getValue())));

  private static final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
  private static final Lock writeLock = readWriteLock.writeLock();
  private static final Lock readLock = readWriteLock.readLock();

  /**
   * 按照优先级添加元素
   * <p>超过限制将移除优先级最低元素,优先级相等则以最后新增元素为主</p>
   *
   * @param key      元素 key
   * @param priority 元素优先级
   * @param value    元素 value
   */
  public static void put(Object key, Integer priority, Object value) {
    writeLock.tryLock();
    try {
      if (ObjectUtils.isEmpty(priorityQueue)) {
        addElement(key, priority, value);
        return;
      }
      // 先从优先级队列中移除旧的元素
      if (priorityQueue.contains(key)) {
        priorityQueue.remove(key);
        lruCache.remove(key);
      }
      // 添加新的元素到优先级队列和缓存中
      addElement(key, priority, value);
      if (priorityQueue.size() > maxSize) {
        Entry<Object, Integer> peek = priorityQueue.peek();
        lruCache.remove(peek.getKey());
        priorityQueue.poll();
      }
    } finally {
      writeLock.unlock();
    }
  }


  /**
   * 添加新的元素到优先级队列和缓存中
   *
   * @param key      元素 key
   * @param priority 元素优先级
   * @param value    元素 value
   */
  private static void addElement(Object key, Integer priority, Object value) {
    priorityQueue.add(new AbstractMap.SimpleEntry<>(key, priority));
    lruCache.put(key, value);
  }

  /**
   * 根据 key 获取缓存的值
   *
   * @param key 缓存 key
   * @return 缓存的 value
   */
  public static Object get(Object key) {
    readLock.tryLock();
    try {
      if (lruCache.containsKey(key)) {
        return lruCache.get(key);
      } else {
        return null;
      }
    } finally {
      readLock.unlock();
    }
  }

  /**
   * 获取无序 key 集合
   *
   * @return 无序 key 集合
   */
  public static Object getPriorityQueue() {
    return priorityQueue;
  }


  /**
   * 获取当前最低优先级元素 <li>kye,优先级</li>
   *
   * @return 最低优先级元素
   */
  public static Entry<Object, Integer> getMinPriorityElement() {
    return priorityQueue.peek();
  }

  /**
   * 设置缓存监听
   *
   * @param listener 监听类
   */
  public static void setListener(CacheListener<Object, Object> listener) {
    lruCache.setListener(listener);
  }


  public static void main(String[] args) {

    PriorityLRUCache.put("a", 1, 8);
    PriorityLRUCache.put("b", 2, 9);
    PriorityLRUCache.put("c", 3, 7);
    System.out.println(JSONUtil.toJsonPrettyStr(PriorityLRUCache.getPriorityQueue()));

    System.out.println(PriorityLRUCache.get("a"));
    System.out.println(PriorityLRUCache.get("b"));
    System.out.println(PriorityLRUCache.get("c"));

    // 低优先级添加
    PriorityLRUCache.put("d", 7, 6);
    // 高优先级添加
//    PriorityLRUCache.put("d", 2, 6);
    // 同优先级添加
//    PriorityLRUCache.put("d", 3, 5);
    System.out.println(JSONUtil.toJsonPrettyStr(PriorityLRUCache.getPriorityQueue()));

    System.out.println(PriorityLRUCache.get("a"));
    System.out.println(PriorityLRUCache.get("b"));
    System.out.println(PriorityLRUCache.get("c"));
    System.out.println(PriorityLRUCache.get("d"));

    PriorityLRUCache.setListener((key, cachedObject) -> {
      System.out.println(key);
      System.out.println(cachedObject);
    });
  }
}

总结

看看长期使用效果如何吧,目前看问题不大,hutool真方便~,虽然站在巨人的肩膀上,做了点优先级的东西,但是还是收获颇丰的.


举报

相关推荐

0 条评论