Java正常关闭资源的方式

在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接、网络连接、磁盘文件等,打开这些物理资源之后必须显式关闭,否则将会引起资源泄漏。

JVM的垃圾回收机制不会回收这些资源,垃圾回收机制属于Java内存管理的一部分,它只是负责回收堆内存中分配出来的内存,至于程序中打开的物理资源,垃圾回收机制是无能为力的。

为了正常关闭程序中打开的物理资源,应该使用finally块来保证回收。

下面程序示范了常见的数据库资源。

importjava.sql.Connection;

importjava.sql.DriverManager;

importjava.sql.PreparedStatement;

importjava.sql.ResultSet;

importjava.sql.SQLException;

 

public class Tester {

 

  public static void main(String[] args) {

      String url = "jdbc:mysql://localhost:3306/test";

      String user = "root";

      String password = "root";

 

      Connection conn = null;

      PreparedStatement pst = null;

      ResultSet rs = null;

 

      try {

         Class.forName("com.mysql.jdbc.Driver");

 

         conn = DriverManager.getConnection(url,user, password);

 

         pst = conn.prepareStatement("select* from test");

 

         rs = pst.executeQuery();

 

         while (rs.next()) {

             System.out.println(rs.getObject(0));

         }

      } catch (ClassNotFoundException e) {

         e.printStackTrace();

      } catch (SQLException e) {

         e.printStackTrace();

      } finally {

         try {

            rs.close();

            pst.close();

            conn.close();

        } catch (SQLException e) {

            e.printStackTrace();

        }

      }

  }

}

虽然程序已经使用finally块来保证资源被关闭,但是这个程序的关闭是不安全的。因为程序开始时指定conn = null;pst = null;rs = null;,完全有可能在程序运行过程中初始化conn之前就引发了异常,那么connpstrs还未来得及初始化,因此它们根本无需关闭。

将上面程序改为如下形式:

importjava.sql.Connection;

importjava.sql.DriverManager;

importjava.sql.PreparedStatement;

importjava.sql.ResultSet;

importjava.sql.SQLException;

 

public class Tester {

 

  public static void main(String[] args) {

      String url = "jdbc:mysql://localhost:3306/test";

      String user = "root";

      String password = "root";

 

      Connection conn = null;

      PreparedStatement pst = null;

      ResultSet rs = null;

 

      try {

         Class.forName("com.mysql.jdbc.Driver");

 

         conn = DriverManager.getConnection(url,user, password);

 

         pst = conn.prepareStatement("select* from test");

 

         rs = pst.executeQuery();

 

         while (rs.next()) {

             System.out.println(rs.getObject(0));

         }

      } catch (ClassNotFoundException e) {

         e.printStackTrace();

      } catch (SQLException e) {

         e.printStackTrace();

      } finally {

         try {

            if(rs != null){

               rs.close();

            }

            

            if(pst != null){

               pst.close();

            }

            

            if(conn != null){

               conn.close();

            }

        } catch (SQLException e) {

            e.printStackTrace();

        }

      }

  }

}

程序首先保存rs不为null才关闭,再保证pst不为null才关闭pst,再保证conn不为null才关闭conn

这样表面看起来安全,实际上并不是这样。假如程序开始已经正常初始化了connpstrs,在关闭rs时出现了异常,那么程序将在关闭rs时非正常退出,这样就会导致pstconn得不到关闭,从而导致资源泄漏。

为了保证关闭各资源时出现的异常不会相互影响,应该在关闭每个资源时分开使用try...catch块来保证关闭操作不会导致程序非正常退出。

importjava.sql.Connection;

importjava.sql.DriverManager;

importjava.sql.PreparedStatement;

importjava.sql.ResultSet;

importjava.sql.SQLException;

 

public class Tester {

 

  public static void main(String[] args) {

      String url = "jdbc:mysql://localhost:3306/test";

      String user = "root";

      String password = "root";

 

      Connection conn = null;

      PreparedStatement pst = null;

      ResultSet rs = null;

 

      try {

         Class.forName("com.mysql.jdbc.Driver");

 

         conn = DriverManager.getConnection(url,user, password);

 

         pst = conn.prepareStatement("select* from test");

 

         rs = pst.executeQuery();

 

          while(rs.next()) {

             System.out.println(rs.getObject(0));

         }

      } catch (ClassNotFoundException e) {

         e.printStackTrace();

      } catch (SQLException e) {

         e.printStackTrace();

      } finally {

         if (rs != null) {

            try {

               rs.close();

            } catch (SQLException e) {

               e.printStackTrace();

            }

        }

 

        if (pst != null) {

            try {

               pst.close();

            } catch (SQLException e) {

               e.printStackTrace();

            }

        }

 

        if (conn != null) {

            try {

               conn.close();

            } catch (SQLException e) {

               e.printStackTrace();

            }

        }

      }

  }

}

上面程序所示的资源关闭方式才是比较安全的,这种关闭方式主要保证如下3点:

1. 使用finally块来关闭物理资源,保证关闭操作总是会被执行;

2. 关闭每个资源之前首先保证引用该资源的引用变量不为null

3. 为每个物理资源使用单独try...catch块关闭资源,保证关闭资源时引发的异常不会影响其他资源的关闭。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当我们在Java中编写关闭钩子代码时,我们需要确保它能够正常关闭程序。下面是一个示例代码,展示了如何编写一个正常关闭的钩子: ```java public class ShutdownHookExample { public static void main(String[] args) { // 注册关闭钩子 Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { // 在这里编写关闭程序前需要执行的代码 System.out.println("正在执行关闭钩子..."); closeResources(); System.out.println("关闭钩子执行完毕"); } }); // 程序主体逻辑 System.out.println("程序正在运行..."); // 模拟程序运行 try { Thread.sleep(5000); // 程序运行 5 秒钟 } catch (InterruptedException e) { e.printStackTrace(); } // 手动触发关闭信号 System.exit(0); } private static void closeResources() { // 在这里编写关闭资源的代码 System.out.println("正在关闭资源..."); // 关闭数据库连接 // 关闭文件流 // ... System.out.println("资源关闭完毕"); } } ``` 在上述示例中,我们创建了一个`ShutdownHookExample`类,其中的`main`方法是程序的入口。我们通过`Runtime.getRuntime().addShutdownHook()`方法注册了一个关闭钩子,该钩子在程序关闭时被触发。 在钩子的`run`方法中,我们编写了关闭程序前需要执行的代码。在示例中,我们打印了一些信息,并调用了`closeResources()`方法来关闭资源。 在程序主体逻辑中,我们模拟了程序的运行,通过`Thread.sleep()`方法让程序运行5秒钟。然后,我们手动触发关闭信号,调用`System.exit(0)`方法来退出程序。 当程序运行时,你会看到输出的信息包括程序正在运行的提示、关闭钩子执行的提示以及资源关闭的提示。这表明钩子代码已经正常执行,并且资源被正确关闭。 请注意,关闭钩子是在主线程结束之前执行的,因此如果你有其他线程在运行,需要确保它们能够正常退出或停止。否则,你可能需要在钩子中处理这些线程的关闭逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值