使用WeakHashMap创建具有过期时间的本地缓存

简介:

java中为了让程序员能参与到垃圾回收机制中(不是说java的GC是全自动的吗?这要看从哪个方面讲了,其实如果开发人员能熟练掌握java的gc原理,对提升系统的稳定性有极大帮助),设计了4种引用级别:分别是强引用(new 出来的)、软引用、弱引用和虚引用。

本文不打算介绍这几种引用的用法。还不了解它们的读者可以自行百度(国内的几个搜索引擎,还是百度 最适合程序员)。
不过如果能使用谷歌的还是要使用谷歌,因为各个级别都有大坑,使用不当可能完全发挥不了期望的效果。但是国内很少有文章讲其中的注意事项,可能是使用的场景太少了。而国外(比如dzone)的博客就不少。

弱引用的对象在每次垃圾回收的时候都会被处理掉。WeakHashMap就是利用了这个特性来实现的本地缓存。

WeakHashMap的具体用法也请百度。这里假设你已经在用WeakHashMap了

WeakHashMap实现的缓存虽然好用,但是不具备定时过期的特性。如果没有等到垃圾回收(或者我不去看监控根本不知道是否进行过垃圾回收),但是想更新缓存之值,就无能为力了!

所以这里我们个WeakHashMap增加一个过期时间。

有两种方式实现:

  • 通过继承WeakHashMap实现
  • 将WeakHashMap作为一个属性来实现

我们这里使用第一种,思路是把本来要放进WeakHashMap的东西附加一个当前时间。所以在写出继承WeakHashMap 的类之前先写一个附加时间点的封装类:

public class TimedLocalCachedDataDTO<V> {
    private final LocalDateTime time;
    private final V data;

    public TimedLocalCachedDataDTO(V data) {
        this.time = LocalDateTime.now();
        this.data = data;
    }
    // getters
}

这样,我们的WeakHashMap要放的对象都是TimedLocalCachedDataDTO 的实例:

public class TimedLocalCache<K, V> extends WeakHashMap<K, TimedLocalCachedDataDTO<V>> {

这个类里,我们给它指定一个过期时间:

public class TimedLocalCache<K, V> extends WeakHashMap<K, TimedLocalCachedDataDTO<V>> {
    private final long timeout;

    public TimedLocalCacheDTO(long timeout) {
        this.timeout = timeout;
    }

    /**
     * 默认5分钟过期
     */
    public TimedLocalCacheDTO() {
        timeout = TimeUnit.MINUTES.toSeconds(5);
    }

    public long getTimeout() {
        return timeout;
    }

然后在获取值的时候,如果根据key获取到值了,并不直接返回;而是先拿到放入的时间点加上过期时间与当前时间比较。下面分别是写入和读取的方法:

    public TimedLocalCachedDataDTO<V> putCache(K key, V value) {
        TimedLocalCachedDataDTO<V> dataDTO = new TimedLocalCachedDataDTO<>(value);
        return super.put(key, dataDTO);
    }
    public V getCache(K key) {
        TimedLocalCachedDataDTO<V> dataDTO = super.get(key);
        if (dataDTO == null) {
            return null;
        }
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime time = dataDTO.getTime();
        long seconds = Duration.between(time, now).getSeconds();
        if (seconds > getTimeout()) {
            remove(key);
            return null;
        }
        return dataDTO.getData();
    }

这样,我们的WeakHashMap就可以指定一个过期时间了,而不用等待JVM垃圾回收。

目录
相关文章
|
缓存 NoSQL Java
Java实现redis缓存效果变量过期
Java实现redis缓存效果变量过期
98 0
|
2月前
|
存储 缓存 NoSQL
Redis过期Key的清理机制
Redis过期Key的清理机制
59 0
|
3月前
|
缓存 前端开发 CDN
静态资源缓存过期时间的设置
【8月更文挑战第18天】静态资源缓存过期时间的设置
80 1
|
6月前
|
缓存 算法 Java
如何实现缓存与LRU算法以及惰性过期
如何实现缓存与LRU算法以及惰性过期
74 1
|
6月前
|
存储 NoSQL Unix
Redis过期键及内存淘汰策略
Redis过期键及内存淘汰策略
|
缓存 NoSQL 算法
Redis之过期key的淘汰及缓存淘汰策略解读
Redis之过期key的淘汰及缓存淘汰策略解读
|
缓存 NoSQL 算法
Redis的数据过期清除策略 与 内存淘汰策略
Redis的数据过期清除策略 与 内存淘汰策略
|
缓存 NoSQL MongoDB
一日一技:实现有过期时间的LRU缓存
一日一技:实现有过期时间的LRU缓存
304 0
手把手教你实现线程安全并且可以设置过期时间的LRU缓存。安排!
1. LRU 缓存介绍 2. ConcurrentLinkedQueue简单介绍 3. ReadWriteLock简单介绍 4.ScheduledExecutorService 简单介绍 5. 徒手撸一个线程安全的 LRU 缓存 6. 实现一个线程安全并且带有过期时间的 LRU 缓存 很多人就会问了:“网上已经有这么多现成的缓存了!为什么面试官还要我们自己实现一个呢?” 。咳咳咳,当然是为了面试需要。哈哈!开个玩笑,我个人觉得更多地是为了学习吧!
|
缓存 NoSQL 算法
理解Redis的内存回收机制和过期淘汰策略
还在等什么,快来一起讨论关注吧,公众号【八点半技术站】,欢迎加入社群