java实现带过期时间的缓存

  1. private static ScheduledExecutorService swapExpiredPool
  2. = new ScheduledThreadPoolExecutor(10);
  3. private ReentrantLock lock = new ReentrantLock();
  4. private ConcurrentHashMap<String, Node> cache = new ConcurrentHashMap<>(1024);
  5. /**
  6. * 让过期时间最小的数据排在队列前,在清除过期数据时
  7. * ,只需查看缓存最近的过期数据,而不用扫描全部缓存
  8. * @see Node#compareTo(Node)
  9. * @see SwapExpiredNodeWork#run()
  10. */
  11. private PriorityQueue<Node> expireQueue = new PriorityQueue<>(1024);
  12. public LocalCache() {
  13. //使用默认的线程池,每5秒清除一次过期数据
  14. //线程池和调用频率 最好是交给调用者去设置。
  15. swapExpiredPool.scheduleWithFixedDelay(
  16. new SwapExpiredNodeWork(), 5, 5, TimeUnit.SECONDS);
  17. }
  18. public Object set(String key, Object value, long ttl) {
  19. Assert.isTrue(StringUtils.hasLength(key), "key can't be empty");
  20. Assert.isTrue(ttl > 0, "ttl must greater than 0");
  21. long expireTime = System.currentTimeMillis() + ttl;
  22. Node newNode = new Node(key, value, expireTime);
  23. lock.lock();
  24. try {
  25. Node old = cache.put(key, newNode);
  26. expireQueue.add(newNode);
  27. //如果该key存在数据,还要从过期时间队列删除
  28. if (old != null) {
  29. expireQueue.remove(old);
  30. return old.value;
  31. }
  32. return null;
  33. } finally {
  34. lock.unlock();
  35. }
  36. }
  37. /**
  38. * 拿到的数据可能是已经过期的数据,可以再次判断一下
  39. * if(n.expireTime<System.currentTimeMillis()){
  40. * return null;
  41. * }
  42. * 也可以直接返回整个节点Node ,交给调用者去取舍
  43. * <p>
  44. * <p>
  45. * 无法判断不存在该key,还是该key存的是一个null值,如果需要区分这两种情况
  46. * 可以定义一个全局标识,标识key不存在
  47. * public static final NOT_EXIST = new Object();
  48. * 返回值时
  49. * return n==null?NOT_EXIST:n.value;
  50. */
  51. public Object get(String key) {
  52. Node n = cache.get(key);
  53. return n == null ? null : n.value;
  54. }
  55. /**
  56. * 删出KEY,并返回该key对应的数据
  57. */
  58. public Object remove(String key) {
  59. lock.lock();
  60. try {
  61. Node n = cache.remove(key);
  62. if (n == null) {
  63. return null;
  64. } else {
  65. expireQueue.remove(n);
  66. return n.value;
  67. }
  68. } finally {
  69. lock.unlock();
  70. }
  71. }
  72. /**
  73. * 删除已经过期的数据
  74. */
  75. private class SwapExpiredNodeWork implements Runnable {
  76. @Override
  77. public void run() {
  78. long now = System.currentTimeMillis();
  79. while (true) {
  80. lock.lock();
  81. try {
  82. Node node = expireQueue.peek();
  83. //没有数据了,或者数据都是没有过期的了
  84. if (node == null || node.expireTime > now) {
  85. return;
  86. }
  87. cache.remove(node.key);
  88. expireQueue.poll();
  89. } finally {
  90. lock.unlock();
  91. }
  92. }
  93. }
  94. }
  95. private static class Node implements Comparable<Node> {
  96. private String key;
  97. private Object value;
  98. private long expireTime;
  99. public Node(String key, Object value, long expireTime) {
  100. this.value = value;
  101. this.key = key;
  102. this.expireTime = expireTime;
  103. }
  104. /**
  105. * @see SwapExpiredNodeWork
  106. */
  107. @Override
  108. public int compareTo(Node o) {
  109. long r = this.expireTime - o.expireTime;
  110. if (r > 0) {
  111. return 1;
  112. }
  113. if (r < 0) {
  114. return -1;
  115. }
  116. return 0;
  117. }
  118. }

原网址: 访问
创建于: 2023-02-22 10:54:13
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论