Java finally 块是否总是运行?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/464098/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does a finally block always run?
提问by Warrior
Is there any condition where finally might not run in java? Thanks.
是否有任何条件最终可能无法在 Java 中运行?谢谢。
采纳答案by hhafez
from the Sun Tutorials
来自Sun 教程
Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.
注意:如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。同样,如果执行 try 或 catch 代码的线程被中断或终止,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。
I don't know of any other ways the finally block wouldn't execute...
我不知道 finally 块不会执行的任何其他方式......
回答by Eugene Yokota
System.exitshuts down the Virtual Machine.
System.exit关闭虚拟机。
Terminates the currently running Java Virtual Machine. The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.
This method calls the
exit
method in classRuntime
. This method never returns normally.
终止当前运行的 Java 虚拟机。参数用作状态代码;按照惯例,非零状态代码表示异常终止。
该方法调用
exit
类中的方法Runtime
。此方法永远不会正常返回。
try {
System.out.println("hello");
System.exit(0);
}
finally {
System.out.println("bye");
} // try-finally
"bye" does not print out in above code.
“再见”不会在上面的代码中打印出来。
回答by Daniel Nadasi
Just to expand on what others have said, anything that does not cause something like the JVM exiting will incur the finally block. So the following method:
只是为了扩展其他人所说的内容,任何不会导致 JVM 退出之类的事情都会导致 finally 块。所以下面的方法:
public static int Stupid() {
try {
return 0;
}
finally {
return 1;
}
}
will strangely both compile and return 1.
会奇怪地编译并返回 1。
回答by Zarkonnen
Related to System.exit, there are also certain types of catastrophic failure where a finally block may not execute. If the JVM runs out of memory entirely, it may just exit without catch or finally happening.
与 System.exit 相关,还有某些类型的灾难性故障,其中 finally 块可能无法执行。如果 JVM 完全耗尽内存,它可能会退出而没有捕获或最终发生。
Specifically, I remember a project where we foolishly tried to use
具体来说,我记得一个我们愚蠢地尝试使用的项目
catch (OutOfMemoryError oome) {
// do stuff
}
This didn't work because the JVM had no memory left for executing the catch block.
这不起作用,因为 JVM 没有剩余内存用于执行 catch 块。
回答by Tom Hawtin - tackline
try { for (;;); } finally { System.err.println("?"); }
In that case the finally will not execute (unless the deprecated Thread.stop
is called, or an equivalent, say, through a tools interface).
在这种情况下,finally 将不会执行(除非Thread.stop
通过工具接口调用deprecated或等效的调用)。
回答by saurabh
The Sun tutorial has been wrongly quoted here in this thread.
在此线程中错误地引用了 Sun 教程。
Note: If the JVM exits while the try or catch code is being executed, then the finally block willnot execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block willnot execute even though the application as a whole continues.
注意:如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块将不会执行。同样,如果执行 try 或 catch 代码的线程被中断或杀死,即使应用程序作为一个整体继续运行,finally 块也不会执行。
If you look into sun tutorial closely for finally block, it doesn't say "will not execute" but "may not execute" Here is the correct description
如果您仔细查看 sun 教程的 finally 块,它不会说“不会执行”而是“可能不会执行”这是正确的描述
Note: If the JVM exits while the try or catch code is being executed, then the finally block maynot execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block maynot execute even though the application as a whole continues.
注意:如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。同样,如果执行 try 或 catch 代码的线程被中断或终止,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。
The apparent reason for this behavior is, call to system.exit() is processed in a runtime system thread which may take time to shutdown the jvm, meanwhile thread scheduler can ask finally to execute. So finally is designed to always execute, but if you are shutting down jvm, it may happen that jvm shuts down prior to finally getting being executed.
这种行为的明显原因是,对 system.exit() 的调用是在运行时系统线程中处理的,这可能需要一些时间来关闭 jvm,同时线程调度程序可以要求最终执行。所以 finally 被设计为始终执行,但是如果您正在关闭 jvm,则 jvm 可能会在最终被执行之前关闭。
回答by wheleph
Also if a deadlock/livelock happens inside try
block.
此外,如果在try
块内发生死锁/活锁。
Here's the code that demonstrates it:
这是演示它的代码:
public class DeadLocker {
private static class SampleRunnable implements Runnable {
private String threadId;
private Object lock1;
private Object lock2;
public SampleRunnable(String threadId, Object lock1, Object lock2) {
super();
this.threadId = threadId;
this.lock1 = lock1;
this.lock2 = lock2;
}
@Override
public void run() {
try {
synchronized (lock1) {
System.out.println(threadId + " inside lock1");
Thread.sleep(1000);
synchronized (lock2) {
System.out.println(threadId + " inside lock2");
}
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
public static void main(String[] args) throws Exception {
Object ob1 = new Object();
Object ob2 = new Object();
Thread t1 = new Thread(new SampleRunnable("t1", ob1, ob2));
Thread t2 = new Thread(new SampleRunnable("t2", ob2, ob1));
t1.start();
t2.start();
}
}
This code produces the following output:
此代码产生以下输出:
t1 inside lock1
t2 inside lock1
and "finally" never gets printed
并且“终于”永远不会被打印出来
回答by Mykhaylo Adamovych
Here are some conditions which can bypass a finally block:
以下是一些可以绕过 finally 块的条件:
- If the JVM exits while the try or catch code is being executed, then the finally block may not execute.
- Normal Shutdown - this occurs either when the last non-daemon thread exits OR when Runtime.exit()
- When a thread exits, the JVM performs an inventory of running threads, and if the only threads that are left are daemon threads, it initiates an orderly shutdown. When the JVM halts, any remaining daemon threads are abandoned finally blocks are not executed, stacks are not unwound the JVM just exits. Daemon threads should be used sparingly few processing activities can be safely abandoned at any time with no cleanup. In particular, it is dangerous to use daemon threads for tasks that might perform any sort of I/O. Daemon threads are best saved for "housekeeping" tasks, such as a background thread that periodically removes expired entries from an in-memory cache.
- 如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。
- 正常关闭 - 这发生在最后一个非守护线程退出或 Runtime.exit() 时
- 当一个线程退出时,JVM 对正在运行的线程进行盘点,如果剩下的线程只有守护线程,它会启动有序关闭。当 JVM 停止时,任何剩余的守护线程都被放弃,finally 块不会被执行,堆栈不会解开,JVM 只是退出。守护线程应该谨慎使用,很少有处理活动可以随时安全地放弃而无需清理。特别是,将守护线程用于可能执行任何类型 I/O 的任务是危险的。守护线程最适合用于“内务处理”任务,例如定期从内存缓存中删除过期条目的后台线程。
Last non-daemon thread exits example:
最后一个非守护线程退出示例:
public class TestDaemon {
private static Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("Is alive");
Thread.sleep(10);
// throw new RuntimeException();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.out.println("This will never be executed.");
}
}
};
public static void main(String[] args) throws InterruptedException {
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
daemon.start();
Thread.sleep(100);
// daemon.stop();
System.out.println("Last non-daemon thread exits.");
}
}
Output:
输出:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
回答by Jeremy Goodell
I've come across a very specific case of the finally block not executing related specifically to the play framework.
我遇到了一个非常特殊的情况,即 finally 块不执行与播放框架相关的特定情况。
I was surprised to find that the finally block in this controller action code only got called after an Exception, but never when the call actually succeeded.
我很惊讶地发现这个控制器动作代码中的 finally 块只在发生异常后才被调用,但在调用实际成功时却从未被调用。
try {
InputStream is = getInputStreamMethod();
renderBinary(is, "out.zip");
catch (Exception e) {
e.printStackTrace();
} finally {
cleanUp();
}
Perhaps the thread is terminated or something when renderBinary() is called. I would suspect the same thing happens for other render() calls, but I didn't verify it.
也许线程被终止或调用 renderBinary() 时发生了什么。我怀疑其他 render() 调用也会发生同样的事情,但我没有验证。
I solved the problem by moving the renderBinary() to after the try/catch. Further investigation revealed that play provides an @Finally annotation to create a method that gets executed after a controller action executes. The caveat here is that this will get called after the execution of ANY action in the controller, so it may not always be a good choice.
我通过将 renderBinary() 移到 try/catch 之后解决了这个问题。进一步的调查显示,play 提供了一个 @Finally 注释来创建一个在控制器操作执行后执行的方法。这里需要注意的是,这将在控制器中执行任何操作后被调用,因此它可能并不总是一个好的选择。
回答by Shyam Arora
//If ArithmeticException Occur Inner finally would not be executed
class Temp
{
public static void main(String[] s)
{
try
{
int x = 10/s.length;
System.out.println(x);
try
{
int z[] = new int[s.length];
z[10] = 1000;
}catch(ArrayIndexOutOfBoundsException e)
{
System.out.println(e);
}
finally
{
System.out.println("Inner finally");
}
}
catch(ArithmeticException e)
{
System.out.println(e);
}
finally
{
System.out.println("Outer Finally");
}
System.out.println("Remaining Code");
}
}