本文目录导读:

我来给你详细讲解Java中过期数据的清理方案,并提供具体的代码示例。
使用定时任务清理过期数据
Timer + TimerTask
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class ExpiredDataCleaner {
// 存储带过期时间的数据
private static Map<String, CacheEntry> cache = new ConcurrentHashMap<>();
static class CacheEntry {
String data;
long expireTime;
CacheEntry(String data, long expireTime) {
this.data = data;
this.expireTime = expireTime;
}
}
public static void main(String[] args) {
// 添加测试数据
cache.put("key1", new CacheEntry("value1", System.currentTimeMillis() + 5000));
cache.put("key2", new CacheEntry("value2", System.currentTimeMillis() + 10000));
cache.put("key3", new CacheEntry("value3", System.currentTimeMillis() + 3000));
// 启动定时清理任务
Timer timer = new Timer(true);
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
cleanExpiredData();
}
}, 0, 2000); // 每2秒执行一次
System.out.println("开始监控过期数据...");
// 让程序运行一会儿观察效果
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
timer.cancel();
System.out.println("最终剩余数据: " + cache.size());
}
private static void cleanExpiredData() {
long currentTime = System.currentTimeMillis();
List<String> expiredKeys = new ArrayList<>();
// 找出过期数据的key
for (Map.Entry<String, CacheEntry> entry : cache.entrySet()) {
if (entry.getValue().expireTime <= currentTime) {
expiredKeys.add(entry.getKey());
}
}
// 删除过期数据
for (String key : expiredKeys) {
cache.remove(key);
System.out.println("清理过期数据: " + key + " at " + new Date());
}
System.out.println("当前缓存大小: " + cache.size());
}
}
ScheduledExecutorService(推荐)
import java.util.concurrent.*;
public class ScheduledCleaner {
private final ConcurrentHashMap<String, CacheItem> cache = new ConcurrentHashMap<>();
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
static class CacheItem {
String value;
long timestamp;
CacheItem(String value, long timestamp) {
this.value = value;
this.timestamp = timestamp;
}
}
public ScheduledCleaner() {
// 启动周期性的清理任务
scheduler.scheduleAtFixedRate(
this::cleanExpired,
0,
1,
TimeUnit.SECONDS // 每秒执行一次
);
}
public void put(String key, String value, long ttl, TimeUnit unit) {
long expireTime = System.currentTimeMillis() + unit.toMillis(ttl);
cache.put(key, new CacheItem(value, expireTime));
}
public String get(String key) {
CacheItem item = cache.get(key);
if (item == null) return null;
// 检查是否过期
if (System.currentTimeMillis() > item.timestamp) {
cache.remove(key);
return null;
}
return item.value;
}
private void cleanExpired() {
long now = System.currentTimeMillis();
cache.entrySet().removeIf(entry -> now > entry.getValue().timestamp);
}
public void shutdown() {
scheduler.shutdown();
}
public static void main(String[] args) throws InterruptedException {
ScheduledCleaner cleaner = new ScheduledCleaner();
// 添加测试数据
cleaner.put("key1", "value1", 3, TimeUnit.SECONDS);
cleaner.put("key2", "value2", 5, TimeUnit.SECONDS);
// 模拟查询
for (int i = 0; i < 10; i++) {
System.out.println("第" + (i+1) + "秒 - key1: " + cleaner.get("key1") +
", key2: " + cleaner.get("key2"));
Thread.sleep(1000);
}
cleaner.shutdown();
}
}
使用缓存框架(推荐)
Guava Cache
import com.google.common.cache.*;
import java.util.concurrent.TimeUnit;
public class GuavaCacheExample {
public static void main(String[] args) throws InterruptedException {
// 创建缓存
Cache<String, String> cache = CacheBuilder.newBuilder()
.maximumSize(100) // 最大缓存数量
.expireAfterWrite(3, TimeUnit.SECONDS) // 写入后3秒过期
.expireAfterAccess(2, TimeUnit.SECONDS) // 访问后2秒过期
.recordStats() // 记录统计信息
.removalListener((RemovalNotification<String, String> notification) -> {
System.out.println(notification.getKey() + " 被移除,原因: " + notification.getCause());
})
.build();
// 添加数据
cache.put("key1", "value1");
cache.put("key2", "value2");
// 查看缓存
System.out.println("key1: " + cache.getIfPresent("key1"));
// 等待过期
Thread.sleep(5000);
System.out.println("5秒后 key1: " + cache.getIfPresent("key1"));
System.out.println("缓存统计: " + cache.stats());
}
}
Caffeine Cache(高性能)
import com.github.benmanes.caffeine.cache.*;
import java.util.concurrent.TimeUnit;
public class CaffeineCacheExample {
public static void main(String[] args) throws InterruptedException {
// 创建缓存
Cache<String, String> cache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(3, TimeUnit.SECONDS)
.expireAfterAccess(2, TimeUnit.SECONDS)
.removalListener((key, value, cause) -> {
System.out.println(key + " 被移除: " + cause);
})
.recordStats()
.build();
// 添加数据
cache.put("key1", "value1");
// 获取数据(自动处理过期)
String value = cache.getIfPresent("key1");
System.out.println("立即获取: " + value);
// 等待过期
Thread.sleep(4000);
System.out.println("4秒后: " + cache.getIfPresent("key1"));
// 查看统计
System.out.println("缓存统计: " + cache.stats());
}
}
手动实现过期清理
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class ManualCleanupExample {
private final ConcurrentHashMap<String, ExpiringValue> map = new ConcurrentHashMap<>();
private final ReadWriteLock lock = new ReentrantReadWriteLock();
static class ExpiringValue {
final String value;
final long expirationTime;
ExpiringValue(String value, long expirationTime) {
this.value = value;
this.expirationTime = expirationTime;
}
}
public void put(String key, String value, long duration, TimeUnit unit) {
long expirationTime = System.currentTimeMillis() + unit.toMillis(duration);
lock.writeLock().lock();
try {
map.put(key, new ExpiringValue(value, expirationTime));
} finally {
lock.writeLock().unlock();
}
}
public String get(String key) {
lock.readLock().lock();
try {
ExpiringValue ev = map.get(key);
if (ev == null) return null;
// 检查是否过期
if (System.currentTimeMillis() > ev.expirationTime) {
// 惰性删除
lock.readLock().unlock();
lock.writeLock().lock();
try {
map.remove(key);
return null;
} finally {
lock.writeLock().unlock();
lock.readLock().lock();
}
}
return ev.value;
} finally {
lock.readLock().unlock();
}
}
// 主动清理过期数据
public void cleanExpired() {
lock.writeLock().lock();
try {
long now = System.currentTimeMillis();
map.entrySet().removeIf(entry -> now > entry.getValue().expirationTime);
} finally {
lock.writeLock().unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ManualCleanupExample cache = new ManualCleanupExample();
// 添加数据
cache.put("key1", "value1", 2, TimeUnit.SECONDS);
cache.put("key2", "value2", 4, TimeUnit.SECONDS);
// 模拟查询和清理
for (int i = 0; i < 6; i++) {
System.out.println("第" + (i+1) + "秒: ");
System.out.println(" key1: " + cache.get("key1"));
System.out.println(" key2: " + cache.get("key2"));
if (i == 3) {
System.out.println("手动清理过期数据...");
cache.cleanExpired();
}
Thread.sleep(1000);
}
}
}
数据库层面处理
import java.sql.*;
import java.util.concurrent.*;
public class DatabaseExpiredCleanup {
// 定时清理数据库过期数据
public void scheduleDbCleanup() {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.scheduleAtFixedRate(() -> {
String sql = "DELETE FROM cache_table WHERE expire_time < NOW()";
try (Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) {
int deleted = stmt.executeUpdate();
if (deleted > 0) {
System.out.println("清理了 " + deleted + " 条过期数据");
}
} catch (SQLException e) {
e.printStackTrace();
}
}, 0, 1, TimeUnit.HOURS); // 每小时执行一次
}
private Connection getConnection() throws SQLException {
// 获取数据库连接
return DriverManager.getConnection("jdbc:mysql://localhost:3306/test",
"user", "password");
}
}
清理策略对比
| 策略 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 定时扫描 | 实现简单、内存友好 | 清理不及时、定时扫描影响性能 | 对实时性要求不高的场景 |
| 惰性删除 | 无额外开销、按需清理 | 过期数据可能长期占用内存 | 对内存不敏感的应用 |
| 缓存框架 | 功能完善、性能优化 | 引入外部依赖 | 企业级应用 |
| 数据库级清理 | 持久化、可靠性高 | 数据库压力、时效性差 | 数据持久化场景 |
最佳实践建议
-
选择合适的清理策略
- 数据量大:推荐使用缓存框架(Guava/Caffeine)
- 对实时性要求高:惰性删除 + 定时扫描结合
- 数据需要持久化:数据库 + 定时任务
-
注意ConcurrentModificationException
// 错误方式 for (Entry entry : map.entrySet()) { if (expired) map.remove(entry.getKey()); } // 正确方式 map.entrySet().removeIf(entry -> expired(entry)); -
考虑使用WeakHashMap
Map<String, Object> weakMap = new WeakHashMap<>(); // 当key没有被其他强引用持有时,GC会自动回收
-
监控和报警
// 添加被清理数据的日志和监控 removalListener((key, value, cause) -> { log.warn("缓存清理: {} -> {}, 原因: {}", key, value, cause); metrics.counter("cache.eviction").inc(); });
这些方案可以根据你的具体需求选择合适的实现方式,建议优先使用成熟的缓存框架,它们已经处理了各种边界情况和性能优化。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播