Java TTL案例

wen java案例 1

本文目录导读:

Java TTL案例

  1. 基于HashMap + 定时器实现简单TTL缓存
  2. 使用ConcurrentHashMap实现线程安全版本
  3. 结合Caffeine实现高性能TTL缓存
  4. Redis实现分布式TTL
  5. 完整使用示例
  6. 使用建议

在Java中实现TTL(Time-To-Live,生存时间)功能通常用于缓存、验证码、会话管理等场景,以下是几种常见的实现方式及完整案例:

基于HashMap + 定时器实现简单TTL缓存

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SimpleTTLCache<K, V> {
    private final Map<K, CacheEntry<V>> cache = new HashMap<>();
    private final ScheduledExecutorService cleanupExecutor = 
            Executors.newSingleThreadScheduledExecutor();
    // 定期清理过期条目
    public SimpleTTLCache() {
        cleanupExecutor.scheduleAtFixedRate(this::cleanupExpiredEntries, 
                1, 1, TimeUnit.SECONDS);
    }
    private static class CacheEntry<V> {
        private final V value;
        private final long expiryTime;
        public CacheEntry(V value, long expiryTime) {
            this.value = value;
            this.expiryTime = expiryTime;
        }
        public boolean isExpired() {
            return System.currentTimeMillis() > expiryTime;
        }
    }
    public void put(K key, V value, long ttlMillis) {
        long expiryTime = System.currentTimeMillis() + ttlMillis;
        cache.put(key, new CacheEntry<>(value, expiryTime));
    }
    public V get(K key) {
        CacheEntry<V> entry = cache.get(key);
        if (entry != null && !entry.isExpired()) {
            return entry.value;
        }
        cache.remove(key);
        return null;
    }
    private void cleanupExpiredEntries() {
        cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
    }
}

使用ConcurrentHashMap实现线程安全版本

import java.util.concurrent.ConcurrentHashMap;
public class ThreadSafeTTLCache<K, V> {
    private final ConcurrentHashMap<K, Entry<V>> cache = new ConcurrentHashMap<>();
    private static class Entry<V> {
        private final V value;
        private final long timestamp;
        private final long ttlMillis;
        public Entry(V value, long ttlMillis) {
            this.value = value;
            this.timestamp = System.currentTimeMillis();
            this.ttlMillis = ttlMillis;
        }
        public boolean isExpired() {
            return System.currentTimeMillis() - timestamp > ttlMillis;
        }
    }
    public void put(K key, V value, long ttlMillis) {
        cache.put(key, new Entry<>(value, ttlMillis));
    }
    public V get(K key) {
        Entry<V> entry = cache.get(key);
        if (entry == null) return null;
        if (entry.isExpired()) {
            cache.remove(key);
            return null;
        }
        return entry.value;
    }
    // 获取剩余TTL
    public long getRemainingTTL(K key) {
        Entry<V> entry = cache.get(key);
        if (entry == null) return -1;
        long remaining = entry.ttlMillis - 
                (System.currentTimeMillis() - entry.timestamp);
        return remaining > 0 ? remaining : -1;
    }
    public void remove(K key) {
        cache.remove(key);
    }
    public int size() {
        // 清理过期条目后再返回大小
        cache.entrySet().removeIf(entry -> entry.getValue().isExpired());
        return cache.size();
    }
}

结合Caffeine实现高性能TTL缓存

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.concurrent.TimeUnit;
public class CaffeineTTLCache {
    private final Cache<String, String> cache;
    public CaffeineTTLCache() {
        cache = Caffeine.newBuilder()
                .maximumSize(10_000)
                .expireAfterWrite(5, TimeUnit.MINUTES)  // 写入后5分钟过期
                .expireAfterAccess(2, TimeUnit.MINUTES) // 访问后2分钟过期
                .recordStats()
                .build();
    }
    public void put(String key, String value) {
        cache.put(key, value);
    }
    public String get(String key) {
        return cache.getIfPresent(key);
    }
    public void invalidate(String key) {
        cache.invalidate(key);
    }
}

Redis实现分布式TTL

import redis.clients.jedis.Jedis;
public class RedisTTLService {
    private Jedis jedis;
    public RedisTTLService(String host, int port) {
        jedis = new Jedis(host, port);
    }
    // 设置带TTL的键值
    public void setWithTTL(String key, String value, int ttlSeconds) {
        jedis.setex(key, ttlSeconds, value);
    }
    // 获取值(Redis会自动删除过期的键)
    public String get(String key) {
        return jedis.get(key);
    }
    // 查看剩余TTL(-2表示键不存在,-1表示永不过期)
    public long getTTL(String key) {
        return jedis.ttl(key);
    }
    // 更新TTL
    public void updateTTL(String key, int ttlSeconds) {
        jedis.expire(key, ttlSeconds);
    }
}

完整使用示例

public class TTLDemo {
    public static void main(String[] args) throws InterruptedException {
        // 演示简单TTL缓存
        SimpleTTLCache<String, String> cache = new SimpleTTLCache<>();
        // 设置2秒后过期
        cache.put("user:1", "张三", 2000);
        System.out.println("第一次获取: " + cache.get("user:1")); // 张三
        Thread.sleep(2500); // 等待2.5秒
        System.out.println("过期后获取: " + cache.get("user:1")); // null
        // 演示线程安全版本
        ThreadSafeTTLCache<String, Integer> safeCache = new ThreadSafeTTLCache<>();
        safeCache.put("count", 100, 1000); // 1秒过期
        System.out.println("剩余TTL: " + safeCache.getRemainingTTL("count")); 
        System.out.println("值: " + safeCache.get("count")); // 100
        // 使用Caffeine(需引入依赖)
        // CaffeineTTLCache caffeineCache = new CaffeineTTLCache();
        // caffeineCache.put("session", "active");
        // System.out.println(caffeineCache.get("session"));
    }
}

使用建议

场景 推荐方案
简单单机应用 HashMap + 定时清理
高并发单机应用 ConcurrentHashMap 或 Caffeine
分布式应用 Redis、Memcached
微服务架构 分布式缓存(Redis)

注意事项:

  1. 定期清理时注意性能影响
  2. 使用滑过时间(sliding expiration)还是固定时间(fixed expiration)
  3. 考虑内存泄漏问题
  4. 分布式环境下需要考虑缓存一致性

您可以根据具体业务场景选择合适的TTL实现方案。

抱歉,评论功能暂时关闭!