本文目录导读:

在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) |
注意事项:
- 定期清理时注意性能影响
- 使用滑过时间(sliding expiration)还是固定时间(fixed expiration)
- 考虑内存泄漏问题
- 分布式环境下需要考虑缓存一致性
您可以根据具体业务场景选择合适的TTL实现方案。