java 最后返回“发生在”之后吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5708834/
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 return "happen after" finally?
提问by Justin
I am trying to convince myself that actions taken in the finally
clause happen beforethe function return (in the memory consistency sense). From the JVM specification, it is clear that within a thread, program order is supposed to drive the happens beforerelationship -- if ahappens bin the program order then ahappens beforeb.
我试图说服自己在finally
子句中采取的行动发生在函数返回之前(在内存一致性意义上)。从JVM规范,很显然,在一个线程中,程序顺序应该是驱动之前发生关系-如果一个发生b按照程序顺序,然后一前发生b。
However, I have not seen anything explicitly stating that finally happens beforereturn, so does it? Or, is there some way that the compiler could reorder the finally
clause since it is simply logging.
但是,我没有看到任何明确说明最终在返回之前发生的事情,是吗?或者,编译器是否可以通过某种方式对finally
子句重新排序,因为它只是记录日志。
Motivating example: I have one thread fetching objects out of a database and am putting them into an ArrayBlockingQueue, and another thread is taking them out. I have some try
- finally
blocks for event timing, and I am seeing after affects of the return beforethe log statement
激励示例:我有一个线程从数据库中提取对象并将它们放入 ArrayBlockingQueue,另一个线程将它们取出。我有一些try
-finally
用于事件计时的块,并且我在日志语句之前看到了返回的影响
Thread 1:
主题 1:
public Batch fetch() {
try {
log("fetch()+");
return queryDatabase();
}
finally {
log("fetch()-");
}
...
workQueue.put(fetch());
Thread 2:
主题 2:
log("take()+");
Batch b = workQueue.take();
log("take()-");
To my great surprise this prints out in an unexpected order. While, yes, logging statements in different threads can appear out of order, there is a time difference of at least 20 ms.
令我惊讶的是,这以意想不到的顺序打印出来。虽然是的,不同线程中的日志语句可能会出现乱序,但至少有 20 毫秒的时间差。
124 ms : take()+
224 ms : fetch()+
244 ms : take()-
254 ms : fetch()-
Note this is not exactly the same question as does finally trump return. I'm not asking what will be returned, but instead about memory consistency and execution order.
请注意,这与finally trump return 的问题并不完全相同。我不是在问将返回什么,而是在问内存一致性和执行顺序。
采纳答案by gcooney
@David Heffernan has the correct answer. The JLS specification talks about the behavior of the return statement(including how it interacts with finally blocks) in section 14.17. Copying from there (emphasis mine):
@David Heffernan 有正确的答案。JLS 规范在 14.17 节中讨论了 return 语句的行为(包括它如何与 finally 块交互)。从那里复制(强调我的):
A return statement with an Expression attempts to transfer control to the invoker of the method that contains it; the value of the Expression becomes the value of the method invocation. More precisely, execution of such a return statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the return statement completes abruptly for that reason. If evaluation of the Expression completes normally, producing a value V, then the return statement completes abruptly, the reason being a return with value V. If the expression is of type float and is not FP-strict (§15.4), then the value may be an element of either the float value set or the float-extended-exponent value set (§4.2.3). If the expression is of type double and is not FP-strict, then the value may be an element of either the double value set or the double-extended-exponent value set.
It can be seen, then, that a return statement always completes abruptly.
The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements (§14.20) within the method or constructor whose try blocks contain the return statement, then any finally clauses of those try statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.
带有表达式的 return 语句试图将控制权转移到包含它的方法的调用者;Expression 的值成为方法调用的值。更准确地说,执行这样的 return 语句首先评估表达式. 如果表达式的计算由于某种原因突然完成,那么 return 语句也会因为这个原因突然完成。如果表达式的计算正常完成,产生值 V,则 return 语句突然完成,原因是返回值为 V。如果表达式的类型为 float 并且不是 FP-strict (§15.4),则该值可以是浮点值集或浮点扩展指数值集(第 4.2.3 节)的元素。如果表达式的类型是 double 并且不是 FP-strict,则该值可以是 double 值集或 double-extended-exponent 值集的元素。
可以看出,return 语句总是突然完成。
前面的描述说“尝试转移控制”而不仅仅是“转移控制”,因为 如果在其 try 块包含 return 语句的方法或构造函数中有任何 try 语句(第 14.20 节),那么这些 try 语句的任何 finally 子句将在控制转移到方法或构造函数的调用者之前,按顺序执行,从最里面到最外面。finally 子句的突然完成可能会中断由 return 语句启动的控制转移。
回答by David Heffernan
The call to queryDatabase()
happens first. Then the finally block. Then control leaves the function (that's the return
).
调用首先queryDatabase()
发生。然后是finally块。然后控制离开函数(即return
)。
回答by Will Marcouiller
The finally
clause shall execute no matter what is the result or behaviour of the try
block, so the finally
gets executed before the return
.
finally
无论try
块的结果或行为是什么,该子句都应执行,因此finally
在return
.
回答by Marcos Vasconcelos
If you are using only one thread, you should see "take+, fetch+, fetch-, take-". In your example, it's multi-threaded, so you are not sure what happens first.
如果你只使用一个线程,你应该看到“take+, fetch+, fetch-, take-”。在您的示例中,它是多线程的,因此您不确定首先会发生什么。