本文目录导读:

- 使用 Guava Cache(最常用)
- 使用 Caffeine(性能更好,Guava的继承者)
- 使用 Redis(分布式场景)
- 手动实现简单缓存(带过期清除)
- 使用 Spring Cache(企业级应用)
- 缓存过期清除的最佳实践
- 选择建议
在Java缓存中设置过期清除,主要有以下几种常见方案,从简单到复杂:
使用 Guava Cache(最常用)
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.Cache;
import java.util.concurrent.TimeUnit;
public class GuavaCacheExample {
public static void main(String[] args) {
// 创建缓存,设置过期策略
Cache<String, Object> cache = CacheBuilder.newBuilder()
// 写入后固定时间过期
.expireAfterWrite(10, TimeUnit.MINUTES)
// 或:访问后固定时间过期(如果一直在访问,就不会过期)
// .expireAfterAccess(30, TimeUnit.MINUTES)
// 最大缓存数量
.maximumSize(1000)
.build();
// 放入缓存
cache.put("key1", "value1");
// 获取缓存
Object value = cache.getIfPresent("key1");
System.out.println(value);
}
}
使用 Caffeine(性能更好,Guava的继承者)
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.concurrent.TimeUnit;
public class CaffeineCacheExample {
public static void main(String[] args) {
Cache<String, Object> cache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES) // 写入后10分钟过期
.expireAfterAccess(30, TimeUnit.MINUTES) // 访问后30分钟过期
.maximumSize(10000) // 最大条目数
.build();
cache.put("user_123", "user_data");
Object data = cache.getIfPresent("user_123");
System.out.println(data);
}
}
使用 Redis(分布式场景)
import redis.clients.jedis.Jedis;
public class RedisCacheExample {
private static final Jedis jedis = new Jedis("localhost", 6379);
// 设置带过期时间的缓存
public static void setWithExpire(String key, String value, int seconds) {
jedis.setex(key, seconds, value); // 设置值并指定过期时间(秒)
}
// 或使用更精确的过期时间
public static void setWithExpireAt(String key, String value, long unixTime) {
jedis.set(key, value);
jedis.expireAt(key, unixTime); // 指定具体过期时间戳
}
public static void main(String[] args) {
// 缓存用户信息,10分钟后过期
setWithExpire("user:123", "{\"name\":\"张三\"}", 600);
// 或:指定具体过期时间(今晚24点过期)
long midnight = System.currentTimeMillis() / 1000 + 86400;
setWithExpireAt("daily_data", "some_value", midnight);
}
}
手动实现简单缓存(带过期清除)
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
public class SimpleCache<K, V> {
private final ConcurrentHashMap<K, CacheEntry<V>> cache = new ConcurrentHashMap<>();
private static class CacheEntry<V> {
V value;
long expireTime;
CacheEntry(V value, long expireTime) {
this.value = value;
this.expireTime = expireTime;
}
}
// 放入缓存,指定过期时间
public void put(K key, V value, long duration, TimeUnit unit) {
long expireTime = System.currentTimeMillis() + unit.toMillis(duration);
cache.put(key, new CacheEntry<>(value, expireTime));
}
// 获取缓存,自动检查是否过期
public V get(K key) {
CacheEntry<V> entry = cache.get(key);
if (entry == null) {
return null;
}
// 检查是否过期
if (System.currentTimeMillis() > entry.expireTime) {
cache.remove(key); // 清除过期缓存
return null;
}
return entry.value;
}
// 定期清理过期缓存(可选)
public void cleanExpired() {
long now = System.currentTimeMillis();
cache.entrySet().removeIf(entry -> now > entry.getValue().expireTime);
}
public static void main(String[] args) throws InterruptedException {
SimpleCache<String, String> cache = new SimpleCache<>();
// 设置缓存,5秒过期
cache.put("key1", "value1", 5, TimeUnit.SECONDS);
System.out.println(cache.get("key1")); // 输出: value1
Thread.sleep(6000); // 等待6秒
System.out.println(cache.get("key1")); // 输出: null(已过期清除)
}
}
使用 Spring Cache(企业级应用)
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
@Service
public class UserService {
// 缓存结果,根据配置自动过期
@Cacheable(value = "users", key = "#userId")
public User getUserById(String userId) {
// 模拟数据库查询
return new User(userId, "张三");
}
// 更新缓存,同时设置过期时间(通过配置)
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
// 更新数据库
return user;
}
// 主动清除缓存
@CacheEvict(value = "users", key = "#userId")
public void deleteUser(String userId) {
// 删除用户
}
}
配置文件(application.yml):
spring:
cache:
type: caffeine
caffeine:
spec: maximumSize=500,expireAfterWrite=10m
缓存过期清除的最佳实践
import com.github.benmanes.caffeine.cache.*;
import java.util.concurrent.TimeUnit;
public class CacheBestPractice {
// 1. 组合过期策略
public static Cache<String, Object> createStrategicCache() {
return Caffeine.newBuilder()
.expireAfter(new Expiry<String, Object>() {
@Override
public long expireAfterCreate(String key, Object value, long currentTime) {
// 不同key设置不同过期时间
if (key.startsWith("session_")) {
return TimeUnit.MINUTES.toNanos(30); // session30分钟
} else if (key.startsWith("temp_")) {
return TimeUnit.SECONDS.toNanos(10); // 临时数据10秒
}
return TimeUnit.MINUTES.toNanos(10); // 默认10分钟
}
@Override
public long expireAfterUpdate(String key, Object value,
long currentTime, long currentDuration) {
return currentDuration; // 更新时不改变过期时间
}
@Override
public long expireAfterRead(String key, Object value,
long currentTime, long currentDuration) {
return currentDuration; // 读取时不改变
}
})
.maximumSize(10000)
.build();
}
// 2. 监听过期事件(清理资源)
public static void main(String[] args) {
Cache<String, Object> cache = Caffeine.newBuilder()
.expireAfterWrite(1, TimeUnit.MINUTES)
.removalListener((key, value, cause) -> {
System.out.println("缓存被清除: " + key +
", 原因: " + cause);
// 如果有需要释放的资源,在这里处理
if (value instanceof AutoCloseable) {
try {
((AutoCloseable) value).close();
} catch (Exception e) {
e.printStackTrace();
}
}
})
.build();
cache.put("temp_file", new TempFile("data.txt"));
// 1分钟后,缓存自动过期,触发移除监听器
}
static class TempFile implements AutoCloseable {
String filename;
TempFile(String filename) { this.filename = filename; }
@Override
public void close() { System.out.println("关闭文件: " + filename); }
}
}
选择建议
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 单机应用 | Caffeine | 性能最好,功能完善 |
| 分布式系统 | Redis | 统一缓存管理 |
| Spring项目 | Spring Cache + Caffeine | 注解简洁,易于维护 |
| 学习/教学 | Guava Cache | API经典,文档丰富 |
使用缓存过期时要注意:
- 合理设置过期时间,不要太长(占用内存)也不要太短(失去缓存意义)
- 考虑缓存穿透问题,使用布隆过滤器等方案
- 敏感数据要设置较短过期时间
- 监控缓存命中率,及时调整过期策略
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播