resource - try catch java7
¿El retorno "sucede después" finalmente? (4)
@David Heffernan tiene la respuesta correcta. La especificación JLS habla sobre el comportamiento de la declaración de devolución (incluida la forma en que interactúa con los bloques finally) en la sección 14.17. Copiando desde allí (énfasis mío):
Una declaración de devolución con una expresión intenta transferir el control al invocador del método que la contiene; el valor de Expression se convierte en el valor de la invocación del método. Más precisamente, la ejecución de dicha declaración de devolución primero evalúa la Expresión . Si la evaluación de Expression se completa abruptamente por algún motivo, la declaración de devolución se completa abruptamente por ese motivo. Si la evaluación de la Expresión se completa normalmente, produciendo un valor V, la declaración de retorno se completa abruptamente, siendo la razón un retorno con valor V. Si la expresión es de tipo flotante y no es FP-estricta (§15.4), entonces el valor puede ser un elemento ya sea del conjunto de valores flotantes o del conjunto de valores flotantes extendidos (§4.2.3). Si la expresión es de tipo double y no es FP-strict, entonces el valor puede ser un elemento del conjunto de valores dobles o del conjunto de valores de doble extensión extendida.
Se puede ver, entonces, que una declaración de retorno siempre se completa abruptamente.
Las descripciones anteriores dicen "intentos de transferir control" en lugar de solo "control de transferencias" porque si hay alguna instrucción try (§14.20) dentro del método o constructor cuyos bloques try contengan la instrucción return, entonces cualquier cláusula finally de esas declaraciones try ser ejecutado, en orden, más interno a más externo, antes de que el control sea transferido al invocador del método o constructor . La terminación abrupta de una cláusula finally puede interrumpir la transferencia de control iniciada por una declaración de devolución.
Estoy tratando de convencerme de que las acciones tomadas en la cláusula finally
suceden antes de que la función regrese (en el sentido de consistencia de la memoria). A partir de la especificación de JVM , está claro que dentro de un hilo, el orden del programa se supone que conduce el pasado antes de la relación - si a sucede b en el orden del programa, entonces sucede antes de b .
Sin embargo, no he visto nada que establezca explícitamente que finalmente suceda antes del regreso, ¿o sí? O bien, ¿hay alguna forma de que el compilador pueda reordenar la cláusula finally
ya que simplemente está registrando?
Ejemplo motivador: Tengo un hilo extrayendo objetos de una base de datos y los estoy colocando en un ArrayBlockingQueue, y otro hilo los está eliminando. Tengo algunos try
- finally
bloquea el tiempo del evento, y estoy viendo después de los efectos de la devolución antes de la declaración de registro
Tema 1:
public Batch fetch() {
try {
log("fetch()+");
return queryDatabase();
}
finally {
log("fetch()-");
}
...
workQueue.put(fetch());
Tema 2:
log("take()+");
Batch b = workQueue.take();
log("take()-");
Para mi gran sorpresa, esto se imprime en un orden inesperado. Si bien, sí, las instrucciones de registro en diferentes subprocesos pueden aparecer desordenadas, existe una diferencia de tiempo de al menos 20 ms.
124 ms : take()+
224 ms : fetch()+
244 ms : take()-
254 ms : fetch()-
Tenga en cuenta que esta no es exactamente la misma pregunta que finalmente triunfo retorno . No estoy preguntando qué será devuelto, sino sobre la consistencia de la memoria y el orden de ejecución.
La cláusula finally
se ejecutará sin importar cuál sea el resultado o el comportamiento del bloque try
, por lo que finally
se ejecuta antes de la return
.
La llamada a queryDatabase()
ocurre primero. Entonces el bloque finalmente. Entonces el control deja la función (ese es el return
).
Si está utilizando solo un hilo, debería ver "tomar +, buscar +, captar-, tomar-". En su ejemplo, tiene varios subprocesos, por lo que no está seguro de qué sucede primero.