Возвращается ли "после"?

Я пытаюсь убедить себя, что действия, выполняемые в предложении finally, происходят до возвращения функции (в смысле последовательности памяти). Из спецификация JVM ясно, что в потоке предполагается, что порядок в программе будет происходить до отношения - если a выполняется b в заказе программы, а затем a происходит до b.

Однако я не видел ничего явно заявляя, что, наконец, это происходит до возвращения, так ли? Или существует способ, которым компилятор может изменить порядок предложения finally, поскольку он просто регистрируется.

Мотивационный пример: у меня есть один поток, который извлекает объекты из базы данных и помещаю их в ArrayBlockingQueue, а другой поток вынимает их. У меня есть несколько блоков try - finally для синхронизации событий, и я вижу после аффектов возврата до оператора журнала

Тема 1:

public Batch fetch() {
    try {
        log("fetch()+");
        return queryDatabase();
    }
    finally {
        log("fetch()-");
    }
     ...
    workQueue.put(fetch());

Тема 2:

log("take()+");
Batch b = workQueue.take();
log("take()-");

К моему большому удивлению, это печатает в неожиданном порядке. Хотя, да, протоколирование операторов в разных потоках может выглядеть не по порядку, разница во времени составляет не менее 20 мкс.

124 ms : take()+
224 ms : fetch()+
244 ms : take()-
254 ms : fetch()-

Обратите внимание, что это не совсем тот же вопрос, что и наконец, возвращает козырь. Я не спрашиваю, что будет возвращено, но вместо этого о согласованности памяти и порядке выполнения.

Ответ 1

@Давид Хеффернан имеет правильный ответ. Спецификация JLS говорит о поведении оператора return (включая его взаимодействие с блоками finally) в разделе 14.17. Копирование оттуда (внимание мое):

Оператор return с выражением попытки передать управление invoker метода, который содержит Это; значение выражения становится значением метода призывание. Точнее, выполнение такого утверждения возврата оценивает выражение. Если оценка выражения выражается по какой-то причине, тогда оператор возврата завершается внезапно по этой причине. Если оценка Выражение завершается нормально, производя значение V, тогда возврат оператор завершается резко, причина - возвращение со значением V. Если выражение имеет тип float и не FP-строгий (§ 15.4), то значение может быть элементом либо поплавка значение или набор значений float-extended-exponent (§4.2.3). Если выражение имеет тип double и не является FP-строгим, то значение может быть элементом либо двойное значение или значение с двойным расширенным показателем.

Таким образом, можно видеть, что возвращение оператор всегда завершается внезапно.

Предыдущие описания говорят "попытки передать контроль" чем просто "передача контроля", потому что , если есть какие-либо утверждения try (§14.20) в рамках метода или конструктор, чьи блоки try содержат выражение о возврате, тогда любое окончательное положения этих заявлений о попытках будут быть выполненным, чтобы, в внешнее, до того, как контроль передан вызывающему метод или конструктор. крутой завершение предложения finally может нарушить передачу контроля инициированный оператором return.

Ответ 2

Сначала вызывается вызов queryDatabase(). Затем блок finally. Тогда управление оставляет функцию (что return).

Ответ 3

Предложение finally должно выполняться независимо от того, что является результатом или поведением блока try, поэтому finally выполняется до return.

Ответ 4

Если вы используете только один поток, вы должны увидеть "take +, fetch +, fetch-, take-". В вашем примере это многопоточное, поэтому вы не знаете, что происходит первым.