Java中自动清理资源的方式(虚引用的作用)

Java中没有析构函数,但可通过finalize、try-with-resource和Cleaner+虚引用机制来清理资源。文章重点讨论了try-with-resource(实现AutoCloseable接口)和Cleaner与PhantomReference的使用,建议尽量使用try-with-resource,而finalize和Cleaner作为兜底。Cleaner通过虚引用关联的引用队列在对象不可达时执行clean方法,实现资源的高效回收。
摘要由CSDN通过智能技术生成

前言

Java是没有析构函数的,所以在一个类的生命周期结束时,它约等于猝死,谁知道啥时候没有人挂念了,系统又要gc了,然后就消失了,什么善后也做不了。但是有许多类都需要显式关闭资源,包括一些本地方法库,甚至JDK自带的很多类都需要(比如OutputStream)。

关闭资源除了人尽皆知的finalize方法,还有更优雅的try-with-resources、虚引用+cleaner方式。本文主要介绍后两种方式,因此也可以说明虚引用的作用。

不过需要强调的是:《Effective Java》一书指出,应尽可能地使用try-with-resourses机制来清理,finalize和cleaner最好作为兜底机制,因为这两种方式不能保证及时清理,甚至由于很大一部分逻辑是由JVM中的GC来实现的,因此不一定保证清理逻辑的执行。

先说说finalize()方法

记得在孤尽老师的课上听Object的8种方法如何记忆的时候,就提到finalize解决了对象的“我要到哪里去”的问题——跑题了

finalize方法从jdk9开始已经标记为废弃了,原因是(下面一段搬砖自jdk11的finalize方法的说明)

The finalization mechanism is inherently problematic. Finalization can lead to performance issues, deadlocks, and hangs. Errors in finalizers can lead to resource leaks; there is no way to cancel finalization if it is no longer necessary; and no ordering is specified among calls to finalize methods of different objects. Furthermore, there are no guarantees regarding the timing of finalization. The finalize method might be called on a finalizable object only after an indefinite delay, if at all. Classes whose instances hold non-heap resources should provide a method to enable explicit release of those resources, and they should also implement AutoCloseable if appropriate. The ref.Cleaner and ref.PhantomReference provide more flexible and efficient ways to release resources when an object becomes unreachable.

简而言之,它有问题(比如无法保证一定执行、何时执行、按什么顺序执行等等),java引入了更优雅的方式进行资源释放。主要有以下几种方式:

  • 实现AutoCloseable接口(try-with-resource)
  • 使用ref.Cleaner和ref.PhantomReference机制

那么,我们就展开说这两种方式。

自动清理资源的两种方式

实现AutoCloseable接口(try-with-resource)

jdk1.7引入了了try-with-resource的用法,大致如下(太懒了直接搬运这篇博文里的代码了)

public class TryWithResource {
   
  public static void main(String[] args) {
   
    try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
       BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
   
      int b;
      while ((b = bin.read()) != -1) {
   
        bout.write(b);
      }
    }
    catch (IOException e) {
   
      e.printStackTrace();
    }
  }
}

简而言之,在语法使用层面上,就是try后面跟一个括号,括号里声明并赋值一个需要显式关闭的资源。相比于之前的try-finally来说,更加优雅。(python也有类似用法,就是with xxx:)

那所有的类都能支持try-with-resource吗?No!但是难度也不大,只要实现了AutoCloseable接口就可以。这里直接搬运该接口的定义和官方说明:

/**
 * An object that may hold resources (such as file or socket handles)
 * until it is closed. The {@link #close()} method of an {@code AutoCloseable}
 * object is called automatically when exiting a {@code
 * try}-with-resources block for which the object has been declared in
 * the resource specification header. This construction ensures prompt
 * release, avoiding resource exhaustion exceptions and errors that
 * may otherwise occur.
 */
public interface AutoCloseable {
   
    void close() throws Exception;
}

简而言之,实现了这个接口,就能用try-with-resources语法。可以看到这个接口内部只有一个方法,就是close()。所以我们也可以想像一下,语法的实现大致就是和try-finally语句块一样,最后调

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值