科普文:一文搞懂jvm实战(一)Runtime实时监控jvm-CSDN博客
科普文:一文搞懂jvm实战(二)Cleaner回收jvm资源-CSDN博客
在前面Cleaner回收jvm资源中,就可以看到 AutoCloseable接口,实现close()方法完成资源回收。

AutoCloseable 是从 jdk7 开始存在的接口,位于 java.lang 包中,用于自动执行资源关闭操作。AutoCloseable 接口定义了一个名为 close() 的方法,用于关闭资源。通常在实现 AutoCloseable 接口的类中重写 close() 方法来实现自定义关闭资源的逻辑,例如关闭文件、释放网络连接等。
AutoCloseable 接口是为了配合 Java 7 引入的 try-with-resources(try-catch-finally) 语句而设计的。使用 try-with-resources 语句可以自动关闭实现了 AutoCloseable 接口的资源,无需显式调用 close() 方法,确保资源在使用完毕后被正确关闭,提高代码的可靠性和安全性。
自动关闭,释放资源机制
在实际的项目开发过程中,一般都有可能连接到一些资源,比如:文件资源、网络资源、数据库资源,在实际项目之中进行资源访问的社会一般有如下几个操作步骤:

手动定义关闭函数
按照正常的结构设计来讲,当前的程序已经可以满足整个设计上的开发要求,因为有正常的连接同时又可以进行服务器断开访问
- import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
- //接口
- interface IMessage{
- public void send(String msg);//发送消息的核心功能
- }
- //实现接口的类
- class NetMassage implements IMessage{
- //无参构造
- //当前的设计为:只要实例化了此类对象就表示要进行消息的发送。则就需要连接网络服务器
- public NetMassage() {
- System.out.println("【连接】连接远程服务器,创建消息的服务通道....");
- }
- @Override
- public void send(String msg) {
- System.out.println("【发送】"+ msg);//模拟数据的发送
- }
- //关闭/释放资源
- public void close(){
- System.out.println("【关闭】网络消息发送完毕,断开服务连接器...");
- }
- }
- public class Application {
- public static void main(String[] args) {
- //实例化
- NetMassage massage = new NetMassage();//创建消息发送类
- massage.send("发送消息啦!!");
- massage.close();//释放资源
- }
- }
-
运行结果如下:
- 【连接】连接远程服务器,创建消息的服务通道....
- 【发送】发送消息啦!!
- 【关闭】网络消息发送完毕,断开服务连接器...
虽然以上代码已经可以正常实现网络消息的处理模型,但当前的程序本身又存在以下几个问题:
必须和异常处理语句一起使用!!!!
- import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
-
- //接口 继承AutoCloseable类(实现自动关闭)
- // AutoCloseable类要和异常捕获一起使用!!!
- interface IMessage extends AutoCloseable{
- public void send(String msg);//发送消息的核心功能
- }
- //实现接口的类
- class NetMassage implements IMessage{
- //无参构造
- //当前的设计为:只要实例化了此类对象就表示要进行消息的发送。则就需要连接网络服务器
- public NetMassage() {
- System.out.println("【连接】连接远程服务器,创建消息的服务通道....");
- }
- @Override
- public void send(String msg) {
- System.out.println("【发送】"+ msg);//模拟数据的发送
- }
- //关闭/释放资源
- public void close(){
- System.out.println("【关闭】网络消息发送完毕,断开服务连接器...");
- }
- }
- public class Application {
- public static void main(String[] args) {
- //AutoCloseable类要和异常处理语句一起使用!!!
- try ( NetMassage massage = new NetMassage();){
- massage.send("发送消息啦!!");
- } catch (Exception e) {
- }
- //massage.close();//释放资源
- }
- }
运行结果如下:
- 【连接】连接远程服务器,创建消息的服务通道....
- 【发送】发送消息啦!!
- 【关闭】网络消息发送完毕,断开服务连接器...
在运行过程中有异常抛出也可以自动关闭: send函数修改如下
- @Override
- public void send(String msg) {
- if(msg.contains("发送消息")){ //手动抛出异常
- throw new RuntimeException("异常抛出!!");
- }
- System.out.println("【发送】"+ msg);//模拟数据的发送
- }
运行结果如下:
- 【连接】连接远程服务器,创建消息的服务通道....
- 【关闭】网络消息发送完毕,断开服务连接器...
通过以上的代码可以发现,必须结合异常处理语句之后才可以使用自动关闭的处理机制,如果在调用的过程之中出现有异常close()方法也是可以正常执行调用的。
- 自定义类实现 AutoCloseable 并重写 close() 方法:
-
- public class StreamExample implements AutoCloseable {
- private BufferedReader reader;
-
- public StreamExample(String filePath) throws IOException {
- reader = new BufferedReader(new FileReader(filePath));
- }
-
- public String readLine() throws IOException {
- return reader.readLine();
- }
-
- /**
- * 重写 close() 方法,自定义关闭资源逻辑
- * @throws IOException
- */
- @Override
- public void close() throws IOException {
- reader.close();
- }
- }
-
- 在 try-catch-finally 中的使用:
-
- public class BaseTest {
- public static void main(String[] args) {
- // 在 try() 中使用自定义对象,在执行完 try 逻辑后会自动调用 close() 方法关闭资源。
- // 这样无需在 catch 或 finally 中编写关闭资源的逻辑了。
- try (StreamExample example = new StreamExample("file.txt")) {
- String line = example.readLine();
- while (line != null) {
- System.out.println(line);
- line = example.readLine();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- 比如在 for 循环语句中,遍历每一个元素时,为每一个元素处理日志设置不同的 traceId,方便日志定位跟踪。
-
-
- @Slf4j
- public class TraceExample implements AutoCloseable {
-
- /**
- * 进入循环之前的traceId
- */
- private String beforeTraceId;
-
- public TraceExample(String beforeTraceId) {
- try {
- this.beforeTraceId = beforeTraceId;
- // 处理不同集合元素使用不同的 traceId,方便定位日志
- String newTraceId = UUID.randomUUID().toString().replaceAll("-", "");
- MDC.put("traceId", newTraceId);
- } catch (Exception e) {
- log.error("TraceExample init error", e);
- }
- }
-
-
- @Override
- public void close() {
- try {
- // 集合处理完后恢复遍历集合之前的 traceId
- MDC.put("traceId", this.beforeTraceId);
- } catch (Exception e) {
- log.error("TraceExample init error", e);
- }
- }
- }
-
-
- 结合 try-catch-finally 在循环语句中使用:
-
-
- public class BaseTest {
- public static void main(String[] args) {
- List
listData = Arrays.asList("1","2", "3"); - for (int i = 0; i < listData.size(); i++) {
- // 在处理元素之前设置新的 traceId,元素处理完后再恢复原 traceId。
- try (TraceExample ignored = new TraceExample("beforeTraceId")) {
- System.out.println("处理元素:" + listData.get(i));
- System.out.println("每个元素处理过程中,新的traceId:" + MDC.get("traceId"));
- } catch (Exception e) {
- throw e;
- }
- System.out.println("原来的 traceId:" + MDC.get("traceId"));
- }
- }
- }