"资源回收就像垃圾分类,及时清理,让程序运行更清爽!" 🌱♻️
🎯 什么是资源回收?
想象一下,你是一个超级忙碌的图书管理员 📚。每天都有很多读者来借书还书,如果借出去的书不及时收回,那图书馆很快就会没有书可借了!
资源回收就像是及时收回借出去的书,让图书馆的资源能够循环使用!
🏃♂️ 核心思想:用及时回收换资源循环,用主动管理换系统稳定
没有回收:资源使用 → 资源耗尽 → 系统崩溃
有回收: 资源使用 → 及时回收 → 资源循环
系统稳定性提升:100%! 🎉
🎨 资源回收的四种策略
1. 及时释放 - 让资源"用完就还" ⏰
生活比喻: 就像借书,看完就还,不要一直占着!
@Service
public class TimelyReleaseService {
// 使用try-with-resources自动释放资源
public String readFileContent(String filePath) {
try (FileInputStream fis = new FileInputStream(filePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
return content.toString();
} catch (IOException e) {
log.error("文件读取失败: {}", filePath, e);
return null;
}
}
// 数据库连接及时释放
public List<User> getUsersFromDatabase() {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.prepareStatement("SELECT * FROM users");
resultSet = statement.executeQuery();
List<User> users = new ArrayList<>();
while (resultSet.next()) {
User user = new User();
user.setId(resultSet.getLong("id"));
user.setName(resultSet.getString("name"));
user.setEmail(resultSet.getString("email"));
users.add(user);
}
return users;
} catch (SQLException e) {
log.error("数据库查询失败", e);
return new ArrayList<>();
} finally {
// 确保资源被释放
closeQuietly(resultSet);
closeQuietly(statement);
closeQuietly(connection);
}
}
// 网络连接及时释放
public String fetchDataFromUrl(String url) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL urlObj = new URL(url);
connection = (HttpURLConnection) urlObj.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
connection.setReadTimeout(10000);
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
return null;
} catch (IOException e) {
log.error("网络请求失败: {}", url, e);
return null;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
log.warn("关闭读取器失败", e);
}
}
if (connection != null) {
connection.disconnect();
}
}
}
// 线程池资源及时释放
public void processTasksWithThreadPool(List<Runnable> tasks) {
ExecutorService executor = Executors.newFixedThreadPool(10);
try {
List<Future<?>> futures = new ArrayList<>();
for (Runnable task : tasks) {
futures.add(executor.submit(task));
}
// 等待所有任务完成
for (Future<?> future : futures) {
try {
future.get(30, TimeUnit.SECONDS);
} catch (TimeoutException e) {
log.warn("任务执行超时", e);
future.cancel(true);
}
}
} finally {
// 确保线程池被关闭
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
// 工具方法:安静地关闭资源
private void closeQuietly(AutoCloseable resource) {
if (resource != null) {
try {
resource.close();
} catch (Exception e) {
log.warn("关闭资源失败", e);
}
}
}
}
2. 弱引用管理 - 让对象"随时可走" 👋
生活比喻: 就像临时工,工作完成就可以随时离开,不会一直占着位置!
@Service
public class WeakReferenceManagementService {
private final Map<String, WeakReference<ExpensiveObject>> weakCache = new ConcurrentHashMap<>();
private final ReferenceQueue<ExpensiveObject> referenceQueue = new ReferenceQueue<>();
// 使用弱引用缓存
public ExpensiveObject getExpensiveObject(String key) {
WeakReference<ExpensiveObject> ref = weakCache.get(key);
ExpensiveObject obj = ref != null ? ref.get() : null;
if (obj == null) {
// 对象已被回收,重新创建
obj = createExpensiveObject(key);
weakCache.put(key, new WeakReference<>(obj, referenceQueue));
log.info("重新创建昂贵对象: {}", key);
} else {
log.info("使用缓存对象: {}", key);
}
// 清理已被回收的弱引用
cleanupWeakReferences();
return obj;
}
// 清理已被回收的弱引用
private void cleanupWeakReferences() {
Reference<? extends ExpensiveObject> ref;
while ((ref = referenceQueue.poll()) != null) {
// 从缓存中移除已被回收的引用
weakCache.entrySet().removeIf(entry -> entry.getValue() == ref);
log.info("清理已被回收的弱引用");
}
}
// 使用软引用管理大对象
public LargeObject getLargeObject(String key) {
SoftReference<LargeObject> ref = softCache.get(key);
LargeObject obj = ref != null ? ref.get() : null;
if (obj == null) {
obj = createLargeObject(key);
softCache.put(key, new SoftReference<>(obj));
log.info("重新创建大对象: {}", key);
}
return obj;
}
private final Map<String, SoftReference<LargeObject>> softCache = new ConcurrentHashMap<>();
// 使用虚引用监控对象回收
public void monitorObjectReclamation(Object obj) {
PhantomReference<Object> phantomRef = new PhantomReference<>(obj, referenceQueue);
monitoredObjects.add(phantomRef);
// 启动监控线程
if (monitoringThread == null) {
startMonitoringThread();
}
}
private final Set<PhantomReference<Object>> monitoredObjects = ConcurrentHashMap.newKeySet();
private volatile Thread monitoringThread;
private void startMonitoringThread() {
monitoringThread = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Reference<?> ref = referenceQueue.remove(1000);
if (ref instanceof PhantomReference) {
monitoredObjects.remove(ref);
log.info("对象已被回收");
// 执行清理操作
performCleanup();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
});
monitoringThread.start();
}
private ExpensiveObject createExpensiveObject(String key) {
// 模拟创建昂贵对象
return new ExpensiveObject(key);
}
private LargeObject createLargeObject(String key) {
// 模拟创建大对象
return new LargeObject(key);
}
private void performCleanup() {
// 执行清理操作
log.info("执行清理操作");
}
// 自定义弱引用缓存
public static class WeakCache<K, V> {
private final Map<K, WeakReference<V>> cache = new ConcurrentHashMap<>();
private final ReferenceQueue<V> queue = new ReferenceQueue<>();
public V get(K key) {
WeakReference<V> ref = cache.get(key);
V value = ref != null ? ref.get() : null;
if (value == null) {
// 清理已被回收的引用
cleanup();
}
return value;
}
public void put(K key, V value) {
cache.put(key, new WeakReference<>(value, queue));
cleanup();
}
private void cleanup() {
Reference<? extends V> ref;
while ((ref = queue.poll()) != null) {
cache.entrySet().removeIf(entry -> entry.getValue() == ref);
}
}
public int size() {
cleanup();
return cache.size();
}
}
}
3. 资源池化 - 让资源"循环使用" 🔄
生活比喻: 就像共享单车,用完了放回停车点,其他人可以继续使用!
@Service
public class ResourcePoolingService {
// 数据库连接池
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("username");
config.setPassword("password");
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
config.setConnectionTimeout(30000);
config.setIdleTimeout(600000);
config.setMaxLifetime(1800000);
return new HikariDataSource(config);
}
// 线程池
@Bean
public ExecutorService threadPool() {
return new ThreadPoolExecutor(
10, // 核心线程数
50, // 最大线程数
60L, TimeUnit.SECONDS, // 空闲时间
new LinkedBlockingQueue<>(100), // 队列
new ThreadFactory() {
private final AtomicInteger threadNumber = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "pool-thread-" + threadNumber.getAndIncrement());
t.setDaemon(false);
return t;
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);
}
// 对象池
public static class ObjectPool<T> {
private final Queue<T> pool = new ConcurrentLinkedQueue<>();
private final Supplier<T> factory;
private final Consumer<T> resetter;
private final int maxSize;
public ObjectPool(Supplier<T> factory, Consumer<T> resetter, int maxSize) {
this.factory = factory;
this.resetter = resetter;
this.maxSize = maxSize;
}
public T borrow() {
T obj = pool.poll();
if (obj == null) {
obj = factory.get();
}
return obj;
}
public void returnObject(T obj) {
if (obj != null && pool.size() < maxSize) {
resetter.accept(obj);
pool.offer(obj);
}
}
public int size() {
return pool.size();
}
}
// 字符串构建器池
private final ObjectPool<StringBuilder> stringBuilderPool = new ObjectPool<>(
StringBuilder::new,
StringBuilder::setLength,
100
);
public String buildString(List<String> parts) {
StringBuilder sb = stringBuilderPool.borrow();
try {
for (String part : parts) {
sb.append(part);
}
return sb.toString();
} finally {
stringBuilderPool.returnObject(sb);
}
}
// HTTP连接池
@Bean
public CloseableHttpClient httpClient() {
PoolingHttpClientConnectionManager connectionManager =
new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(20);
return HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(RequestConfig.custom()
.setConnectTimeout(5000)
.setSocketTimeout(10000)
.build())
.build();
}
// 缓存池
public static class CachePool<K, V> {
private final Map<K, V> cache = new ConcurrentHashMap<>();
private final Queue<K> accessOrder = new ConcurrentLinkedQueue<>();
private final int maxSize;
public CachePool(int maxSize) {
this.maxSize = maxSize;
}
public V get(K key) {
V value = cache.get(key);
if (value != null) {
// 更新访问顺序
accessOrder.remove(key);
accessOrder.offer(key);
}
return value;
}
public void put(K key, V value) {
if (cache.size() >= maxSize) {
// 移除最久未访问的项
K oldestKey = accessOrder.poll();
if (oldestKey != null) {
cache.remove(oldestKey);
}
}
cache.put(key, value);
accessOrder.offer(key);
}
public void clear() {
cache.clear();
accessOrder.clear();
}
public int size() {
return cache.size();
}
}
}
4. 智能回收策略 - 让回收"聪明"起来 🧠
生活比喻: 就像智能垃圾分类,自动识别什么该回收,什么时候回收!
@Service
public class IntelligentRecyclingService {
private final Map<String, ResourceInfo> resourceRegistry = new ConcurrentHashMap<>();
private final ScheduledExecutorService cleanupScheduler = Executors.newScheduledThreadPool(2);
@PostConstruct
public void initializeCleanupScheduler() {
// 定期清理过期资源
cleanupScheduler.scheduleAtFixedRate(this::cleanupExpiredResources,
0, 60, TimeUnit.SECONDS);
// 定期清理未使用资源
cleanupScheduler.scheduleAtFixedRate(this::cleanupUnusedResources,
0, 300, TimeUnit.SECONDS);
}
// 注册资源
public void registerResource(String resourceId, Object resource, long ttlMillis) {
ResourceInfo info = new ResourceInfo(resource, System.currentTimeMillis(), ttlMillis);
resourceRegistry.put(resourceId, info);
log.info("资源已注册: {}", resourceId);
}
// 获取资源
public Object getResource(String resourceId) {
ResourceInfo info = resourceRegistry.get(resourceId);
if (info != null) {
info.updateLastAccess();
return info.getResource();
}
return null;
}
// 清理过期资源
private void cleanupExpiredResources() {
long currentTime = System.currentTimeMillis();
resourceRegistry.entrySet().removeIf(entry -> {
ResourceInfo info = entry.getValue();
boolean expired = currentTime - info.getCreationTime() > info.getTtlMillis();
if (expired) {
log.info("清理过期资源: {}", entry.getKey());
cleanupResource(info.getResource());
}
return expired;
});
}
// 清理未使用资源
private void cleanupUnusedResources() {
long currentTime = System.currentTimeMillis();
long unusedThreshold = 300000; // 5分钟
resourceRegistry.entrySet().removeIf(entry -> {
ResourceInfo info = entry.getValue();
boolean unused = currentTime - info.getLastAccessTime() > unusedThreshold;
if (unused) {
log.info("清理未使用资源: {}", entry.getKey());
cleanupResource(info.getResource());
}
return unused;
});
}
// 基于内存压力的智能回收
public void performMemoryPressureCleanup() {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
double usageRatio = (double) heapUsage.getUsed() / heapUsage.getMax();
if (usageRatio > 0.8) {
log.warn("内存使用率过高: {}%, 开始清理", usageRatio * 100);
// 清理最久未使用的资源
resourceRegistry.entrySet().stream()
.sorted((a, b) -> Long.compare(a.getValue().getLastAccessTime(),
b.getValue().getLastAccessTime()))
.limit(resourceRegistry.size() / 4) // 清理25%的资源
.forEach(entry -> {
log.info("内存压力清理资源: {}", entry.getKey());
cleanupResource(entry.getValue().getResource());
resourceRegistry.remove(entry.getKey());
});
}
}
// 基于访问频率的智能回收
public void performFrequencyBasedCleanup() {
Map<String, Long> accessCounts = new HashMap<>();
// 统计访问频率
resourceRegistry.forEach((key, info) -> {
accessCounts.put(key, info.getAccessCount());
});
// 清理低频访问的资源
long averageAccess = accessCounts.values().stream()
.mapToLong(Long::longValue)
.average()
.orElse(0);
resourceRegistry.entrySet().removeIf(entry -> {
long accessCount = entry.getValue().getAccessCount();
boolean lowFrequency = accessCount < averageAccess * 0.5;
if (lowFrequency) {
log.info("清理低频访问资源: {}", entry.getKey());
cleanupResource(entry.getValue().getResource());
}
return lowFrequency;
});
}
private void cleanupResource(Object resource) {
if (resource instanceof AutoCloseable) {
try {
((AutoCloseable) resource).close();
} catch (Exception e) {
log.warn("资源清理失败", e);
}
}
}
private static class ResourceInfo {
private final Object resource;
private final long creationTime;
private final long ttlMillis;
private volatile long lastAccessTime;
private volatile long accessCount;
ResourceInfo(Object resource, long creationTime, long ttlMillis) {
this.resource = resource;
this.creationTime = creationTime;
this.ttlMillis = ttlMillis;
this.lastAccessTime = creationTime;
this.accessCount = 0;
}
Object getResource() {
return resource;
}
long getCreationTime() {
return creationTime;
}
long getTtlMillis() {
return ttlMillis;
}
long getLastAccessTime() {
return lastAccessTime;
}
long getAccessCount() {
return accessCount;
}
void updateLastAccess() {
this.lastAccessTime = System.currentTimeMillis();
this.accessCount++;
}
}
}
🎯 资源回收的实际应用
1. 数据库连接池管理 🗄️
@Service
public class DatabaseConnectionPoolService {
@Autowired
private DataSource dataSource;
// 使用连接池执行查询
public List<Map<String, Object>> executeQuery(String sql, Object... params) {
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
// 设置参数
for (int i = 0; i < params.length; i++) {
statement.setObject(i + 1, params[i]);
}
// 执行查询
try (ResultSet resultSet = statement.executeQuery()) {
List<Map<String, Object>> results = new ArrayList<>();
ResultSetMetaData metaData = resultSet.getMetaData();
int columnCount = metaData.getColumnCount();
while (resultSet.next()) {
Map<String, Object> row = new HashMap<>();
for (int i = 1; i <= columnCount; i++) {
String columnName = metaData.getColumnName(i);
Object value = resultSet.getObject(i);
row.put(columnName, value);
}
results.add(row);
}
return results;
}
} catch (SQLException e) {
log.error("数据库查询失败", e);
return new ArrayList<>();
}
}
// 批量操作
public int[] executeBatch(String sql, List<Object[]> batchParams) {
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(sql)) {
connection.setAutoCommit(false);
for (Object[] params : batchParams) {
for (int i = 0; i < params.length; i++) {
statement.setObject(i + 1, params[i]);
}
statement.addBatch();
}
int[] results = statement.executeBatch();
connection.commit();
return results;
} catch (SQLException e) {
log.error("批量操作失败", e);
return new int[0];
}
}
}
2. 文件资源管理 📁
@Service
public class FileResourceManagementService {
// 文件流池
private final ObjectPool<BufferedReader> readerPool = new ObjectPool<>(
() -> new BufferedReader(new StringReader("")),
reader -> {
try {
reader.close();
} catch (IOException e) {
log.warn("关闭读取器失败", e);
}
},
50
);
// 安全读取文件
public String readFileSafely(String filePath) {
try (FileInputStream fis = new FileInputStream(filePath);
BufferedReader reader = new BufferedReader(new InputStreamReader(fis))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
return content.toString();
} catch (IOException e) {
log.error("文件读取失败: {}", filePath, e);
return null;
}
}
// 安全写入文件
public boolean writeFileSafely(String filePath, String content) {
try (FileOutputStream fos = new FileOutputStream(filePath);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos))) {
writer.write(content);
writer.flush();
return true;
} catch (IOException e) {
log.error("文件写入失败: {}", filePath, e);
return false;
}
}
// 临时文件管理
public String createTemporaryFile(String content) {
try {
File tempFile = File.createTempFile("temp_", ".txt");
tempFile.deleteOnExit(); // 程序结束时自动删除
try (FileWriter writer = new FileWriter(tempFile)) {
writer.write(content);
}
return tempFile.getAbsolutePath();
} catch (IOException e) {
log.error("创建临时文件失败", e);
return null;
}
}
}
🛡️ 资源回收的注意事项
1. 资源泄漏检测 🔍
@Service
public class ResourceLeakDetectionService {
private final Map<String, ResourceTracker> resourceTrackers = new ConcurrentHashMap<>();
// 跟踪资源使用
public void trackResource(String resourceId, Object resource) {
ResourceTracker tracker = new ResourceTracker(resourceId, resource);
resourceTrackers.put(resourceId, tracker);
log.info("开始跟踪资源: {}", resourceId);
}
// 释放资源并停止跟踪
public void releaseResource(String resourceId) {
ResourceTracker tracker = resourceTrackers.remove(resourceId);
if (tracker != null) {
tracker.release();
log.info("资源已释放: {}", resourceId);
}
}
// 检测资源泄漏
@Scheduled(fixedRate = 60000) // 每分钟检查一次
public void detectResourceLeaks() {
long currentTime = System.currentTimeMillis();
long leakThreshold = 300000; // 5分钟
List<String> leakedResources = resourceTrackers.entrySet().stream()
.filter(entry -> currentTime - entry.getValue().getCreationTime() > leakThreshold)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
if (!leakedResources.isEmpty()) {
log.warn("检测到可能的资源泄漏: {}", leakedResources);
// 自动清理泄漏的资源
for (String resourceId : leakedResources) {
releaseResource(resourceId);
}
}
}
private static class ResourceTracker {
private final String resourceId;
private final Object resource;
private final long creationTime;
ResourceTracker(String resourceId, Object resource) {
this.resourceId = resourceId;
this.resource = resource;
this.creationTime = System.currentTimeMillis();
}
void release() {
if (resource instanceof AutoCloseable) {
try {
((AutoCloseable) resource).close();
} catch (Exception e) {
log.warn("资源释放失败: {}", resourceId, e);
}
}
}
String getResourceId() { return resourceId; }
Object getResource() { return resource; }
long getCreationTime() { return creationTime; }
}
}
2. 资源使用监控 📊
@Component
public class ResourceUsageMonitor {
private final MeterRegistry meterRegistry;
private final Gauge activeConnections;
private final Gauge memoryUsage;
private final Counter resourceLeaks;
public ResourceUsageMonitor(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.activeConnections = Gauge.builder("resource.active.connections")
.register(meterRegistry, this, ResourceUsageMonitor::getActiveConnections);
this.memoryUsage = Gauge.builder("resource.memory.usage")
.register(meterRegistry, this, ResourceUsageMonitor::getMemoryUsage);
this.resourceLeaks = Counter.builder("resource.leaks")
.register(meterRegistry);
}
public void recordResourceLeak() {
resourceLeaks.increment();
}
private double getActiveConnections() {
// 返回活跃连接数
return 0.0;
}
private double getMemoryUsage() {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
return (double) heapUsage.getUsed() / heapUsage.getMax();
}
}
🎉 总结:资源回收让程序"绿色"环保
资源回收就像生活中的各种"环保"行为:
- 及时释放 = 用完就还,不占着资源 ♻️
- 弱引用管理 = 临时工随时可走 👋
- 资源池化 = 共享资源循环使用 🔄
- 智能回收 = 智能垃圾分类回收 🧠
通过合理使用资源回收,我们可以:
- 🚀 大幅提升系统稳定性
- 💰 减少资源浪费
- ⚡ 改善系统性能
- 🎯 提高资源利用率
记住:资源回收不是浪费,而是环保的智慧! 合理使用资源回收,让你的Java应用运行更稳定! ✨
"资源回收就像魔法,让程序绿色环保,让资源循环使用!" 🪄♻️