问题的提出
当系统执行到程序catch中的return时,系统是否会执行里面的finally语句?
下面的运行结果?
public class CloseTest {
public static void main(String[] args) {
int i = test();
System.out.println(i);
}
private static int test() {
// TODO Auto-generated method stub
try {
System.out.println(123);
return 1;
} catch (Exception e) {
// TODO: handle exception
} finally {
System.out.println(345);
return 2;
}
}
}
是下面的结果吗??
123
1
错!正确的 结果是:
123
345
2
原理:
当java程序执行完try、catch语句块的时候,遇到了return语句,会导致该程序块立刻结束。但是系统执行return语句后,并不会立刻结束该方法,而是去需找该异常处理的流程中是否包含有finally语句:1、如果没有finally,立刻返回
2、有finally语句不会立刻返回,而是需要执行完finally语句中的程序块。
问题的变化(try、catch语句块中时遇到)
如下面的例子:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.imageio.stream.FileImageInputStream;
public class ExitFile {
/**
* @param args
* @throws IOException
* @throws FileNotFoundException
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
File file=new File("c://22.log");
FileImageInputStream fiInputStream = null;
try {
fiInputStream = new FileImageInputStream(file);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (fiInputStream!=null) {
try {
fiInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
我们通过前面的可以知道,当打开文件的时候出现了异常的时候,系统会执行finally语句关闭掉资源,但是当加入System.exit(0) 系统将不会执行finally语句,而是立刻停止当前的线程。
public class ExitFile {
/**
* @param args
* @throws IOException
* @throws FileNotFoundException
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
File file=new File("c://22.log");
FileImageInputStream fiInputStream = null;
try {
fiInputStream = new FileImageInputStream(file);
System.exit(0);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
if (fiInputStream!=null) {
try {
System.out.println("关闭资源");
fiInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
//close 相关的注册的资源
}
});
ps:API文档的相关的描述
addShutdownHook
public void addShutdownHook(Thread hook)
-
注册新的虚拟机来关闭钩子。
Java 虚拟机会为了响应以下两类事件而关闭:
- 程序正常退出,这发生在最后的非守护线程退出时,或者在调用
exit
(等同于System.exit
)方法时。或者, - 为响应用户中断而终止 虚拟机,如键入 ^C;或发生系统事件,比如用户注销或系统关闭。
关闭钩子 只是一个已初始化但尚未启动的线程。虚拟机开始启用其关闭序列时,它会以某种未指定的顺序启动所有已注册的关闭钩子,并让它们同时运行。运行完所有的钩子后,如果已启用退出终结,那么虚拟机接着会运行所有未调用的终结方法。最后,虚拟机会暂停。注意,关闭序列期间会继续运行守护线程,如果通过调用
exit
方法来发起关闭序列,那么也会继续运行非守护线程。一旦开始了关闭序列,则只能通过调用
halt
方法来停止这个序列,此方法可强行终止虚拟机。一旦开始了关闭序列,则不可能注册新的关闭钩子或取消注册先前已注册的钩子。尝试执行这些操作会导致抛出
IllegalStateException
。关闭钩子可在虚拟机生命周期中的特定时间运行,因此应保护性地对其进行编码。特别是应将关闭钩子编写为线程安全的,并尽可能地避免死锁。关闭钩子还应该不盲目地依靠某些服务,这些服务可能已注册了自己的关闭钩子,所以其本身可能正处于关闭进程中。例如,试图使用其他基于线程的服务(如 AWT 事件指派线程)可能导致死锁。
关闭钩子应该快速地完成其工作。当程序调用
exit
时,虚拟机应该迅速地关闭并退出。由于用户注销或系统关闭而终止虚拟机时,底层的操作系统可能只允许在固定的时间内关闭并退出。因此在关闭钩子中尝试进行任何用户交互或执行长时间的计算都是不明智的。与其他所有线程一样,通过调用线程
ThreadGroup
对象的uncaughtException
方法,可在关闭钩子中处理未捕获的异常。此方法的默认实现是将该异常的堆栈跟踪打印至System.err
并终止线程;它不会导致虚拟机退出或暂停。仅在很少的情况下,虚拟机可能会中止,也就是没有完全关闭就停止运行。虚拟机被外部终止时会出现这种现象,比如在 Unix 上使用 SIGKILL 信号或者在 Microsoft Windows 上调用TerminateProcess。如果由于内部数据结构损坏或试图访问不存在的内存而导致本机方法执行错误,那么可能也会中止虚拟机。如果虚拟机中止,则无法保证是否将运行关闭钩子。
-
-
参数:
-
hook
- 一个已初始化但尚未启动的Thread
对象
-
PS: 注册的虚拟机关闭的钩子对于android来说是不实用的
原文
Registers a VM shutdown hook. A shutdown hook is aThreadthat is ready to run, but has not yet been started. All registered shutdown hooks will be executed when the VM terminates normally (typically when theexit(int)method is called).
Note that on Android, the application lifecycle does not include VM termination, so calling this method will not ensure that your code is run. Instead, you should use the most appropriate lifecycle notification (Activity.onPause, say).