简体   繁体   English

最后返回“发生在”之后吗?

[英]Does return "happen after" finally?

I am trying to convince myself that actions taken in the finally clause happen before the function return (in the memory consistency sense).我试图说服自己在finally子句中采取的行动发生在函数返回之前(在内存一致性意义上)。 From the JVM specification , it is clear that within a thread, program order is supposed to drive the happens before relationship -- if a happens b in the program order then a happens before b .JVM规范,很显然,在一个线程中,程序顺序应该是驱动的关系之前发生-如果发生b。在程序顺序则b之前发生

However, I have not seen anything explicitly stating that finally happens before return, 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.激励示例:我有一个线程从数据库中提取对象并将它们放入 ArrayBlockingQueue,另一个线程将它们取出。 I have some try - finally blocks for event timing, and I am seeing after affects of the return before the log statement我有一些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 .请注意,这与finally trump return 的问题并不完全相同。 I'm not asking what will be returned, but instead about memory consistency and execution order.我不是在问将返回什么,而是在问内存一致性和执行顺序。

The call to queryDatabase() happens first.queryDatabase()的调用首先发生。 Then the finally block.然后是finally块。 Then control leaves the function (that's the return ).然后控制离开函数(即return )。

@David Heffernan has the correct answer. @David Heffernan 有正确答案。 The JLS specification talks about the behavior of the return statement(including how it interacts with finally blocks) in section 14.17. JLS 规范在 14.17 节中讨论了 return 语句的行为(包括它如何与 finally 块交互)。 Copying from there (emphasis mine):从那里复制(强调我的):

A return statement with an Expression attempts to transfer control to the invoker of the method that contains it;带有表达式的 return 语句试图将控制权转移到包含它的方法的调用者; the value of the Expression becomes the value of the method invocation. Expression 的值成为方法调用的值。 More precisely, execution of such a return statement first evaluates the Expression .更准确地说,执行这样的 return 语句首先评估 Expression If the evaluation of the Expression completes abruptly for some reason, then the return statement completes abruptly for that reason.如果表达式的计算由于某种原因突然完成,那么 return 语句也会因为这个原因突然完成。 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).如果表达式的计算正常完成,产生值 V,则 return 语句突然完成,原因是返回值为 V。如果表达式是 float 类型且不是 FP-strict(第 15.4 节),则值可以是浮点值集或浮点扩展指数值集(第 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.如果表达式的类型是 double 并且不是 FP-strict,则该值可以是 double 值集或 double-extended-exponent 值集的元素。

It can be seen, then, that a return statement always completes abruptly.可以看出,return 语句总是突然完成。

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 .前面的描述说“尝试转移控制”而不仅仅是“转移控制”,因为如果在其 try 块包含 return 语句的方法或构造函数中有任何 try 语句(第 14.20 节),那么这些 try 语句的任何 finally 子句将在控制转移到方法或构造函数的调用者之前,按顺序执行,从最里面到最外面 Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement. finally 子句的突然完成可能会中断由 return 语句启动的控制转移。

无论try块的结果或行为如何, finally子句都将执行,因此finallyreturn之前执行。

If you are using only one thread, you should see "take+, fetch+, fetch-, take-".如果你只使用一个线程,你应该看到“take+, fetch+, fetch-, take-”。 In your example, it's multi-threaded, so you are not sure what happens first.在您的示例中,它是多线程的,因此您不确定首先会发生什么。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM