Возвращается ли "после"?
Я пытаюсь убедить себя, что действия, выполняемые в предложении 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-". В вашем примере это многопоточное, поэтому вы не знаете, что происходит первым.