No retorno «sucederá después de la» finalmente?

Estoy tratando de convencerme de que las acciones tomadas en el finally cláusula suceder antes de la función de devolución (en la memoria de coherencia de sentido). Desde el JVM especificación, es claro que dentro de un hilo, programa de orden se supone que la unidad de la sucede antes de relación, si un sucede b en el programa de fin de a continuación, un sucede antes de b.

Sin embargo, no he visto nada que se afirma explícitamente que finalmente sucede antes de de retorno, por lo que hace? O, ¿hay alguna manera de que el compilador podría reordenar el finally cláusula dado que se trata simplemente de registro.

Motivar ejemplo: tengo un hilo de busqueda de objetos de una base de datos y estoy poniendo en un ArrayBlockingQueue, y otro hilo está llevando a cabo. Tengo algunas tryfinally bloques para la sincronización de eventos, y estoy viendo después de los efectos de la devolución antes de la instrucción de registro de

Subproceso 1:

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

Subproceso 2:

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

Para mi gran sorpresa, este se imprime en un orden inesperado. Aunque, eso sí, el registro de declaraciones en diferentes hilos pueden aparecer fuera de orden, hay una diferencia de tiempo de al menos 20 ms.

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

Nota que esto no es exactamente la misma pregunta que finalmente el triunfo de retorno. No estoy preguntando qué va a ser devuelto, sino sobre la memoria de la coherencia y orden de ejecución.

  • +1 pregunta Interesante! =)
  • Alguien hizo una muy interesante sobre la función devuelve no ser instrucciones que podrían ser re-ordenadas, luego se borra. Si la pones de nuevo, voy a votar por ella como útil-parecía una muy buena línea de búsqueda aunque con inline + jit reordenar no estoy seguro de que es cierto.
  • Yo atributo de los resultados de mi prueba de la mala memoria, yo tenía un 1 bit de error en el último bit de varias direcciones (por ejemplo, FFFF se escriben como FFFE). Que puede estar seguro de lo que esto hizo que el JIT.
InformationsquelleAutor Justin | 2011-04-18

4 Kommentare

  1. 17

    @David Heffernan tiene la respuesta correcta. El JLS especificación habla sobre el comportamiento de la instrucción return(incluyendo la forma en que interactúa con los bloques finally) en la sección 14.17. Copiar de allí (el énfasis es mío):

    Una instrucción return con una Expresión
    los intentos de transferir el control a la
    invocador del método que contiene
    ella; el valor de la Expresión
    se convierte en el valor del método
    invocación. Más precisamente, la ejecución de
    de tal instrucción return primera
    evalúa la Expresión
    . Si el
    evaluación de la Expresión completa
    abruptamente por alguna razón, entonces el
    instrucción return termina abruptamente
    por esa razón. Si la evaluación de la
    La expresión completa normalmente,
    la producción de un valor de V, entonces el retorno
    la declaración finaliza abruptamente, la
    la razón de ser de un retorno con valor de V. Si
    la expresión es de tipo float y es
    no FP-estricto (artículo 15.4), entonces el valor de
    puede ser un elemento de la flotación
    establece el valor o el
    float-extended-valor de exponente conjunto
    (§4.2.3). Si la expresión es de tipo
    doble y no es FP-estricta, entonces el
    el valor puede ser un elemento de la
    doble conjunto de valores o la
    doble extendida exponente valor establecido.

    Puede ser visto, entonces, que una vuelta
    declaración de siempre termina abruptamente.

    Las anteriores descripciones dicen
    «los intentos de control de transferencia», en lugar
    que «las transferencias de control» porque
    si hay algún try
    (§14.20) dentro del método o
    constructor de cuyos bloques try contener
    la instrucción return, entonces cualquier finalmente
    las cláusulas de los trate de declaraciones de
    ser ejecutado, en fin, más íntimo a
    ultraperiféricas, antes de que el control es
    transferido a la invocador de la
    método o constructor
    . Abrupto
    finalización de una cláusula finally puede
    interrumpir la transferencia de control
    iniciado por una instrucción return.

    • Este pasaje también se hace referencia en el ‘finalmente el triunfo de retorno’, de MODO que la pregunta. Si entiendo su énfasis, finalmente el debe antes de venir a la vuelta en el programa de orden, ya que, por el último pasaje, «antes de que el control se transfiere al invocador del método»
    • Yo realmente deseo que entiende cómo llegó a ser que el registro mostró el otro lado, mi JVM a veces se bloquea, inexplicablemente, así que …
    • El registro puede tener un poco de retraso, construido en. Creo que sólo se sincronizan en la cola, no la de registro.
    • Debe ser eso, pero la mayoría del tiempo, las declaraciones que podrían ser registrados aparecen en el mismo milisegundo-no 20 ms aparte. Sé que no es científica, pero parece convincente en un sentido anecdótico.
    • Yo no creo que hay un pasa-antes de borde entre el final y el retorno. El párrafo anterior no menciona nada sobre el inter-hilo de visibilidad. El JLS es bastante claro acerca de lo que ofrece sucede-antes de: java.sun.com/docs/books/jls/third_edition/html/…
    • El fin y el regreso se producen en el mismo hilo. Porque están en el mismo hilo, el pasa-antes de que la relación está cubierto por la primera viñeta en la sección de enlace.
    • El «ocurre antes de» el lenguaje es un poco de una mala elección, porque en el contexto de JLS, ocurre antes de que se utiliza siempre en el contexto de la rosca de la visibilidad, y no para describir un intra-hilo de la secuencia.
    • Cierto, pero pensé que estaba viendo el efecto de la devolución en otro hilo antes de que el último (posiblemente como resultado de la inlineing). Yo no sé realmente qué tan profundo es el JIT puede ir.
    • Estoy de acuerdo que es realmente la ejecución de la orden se le preguntó acerca de aquí. Lla finalmente definitivamente va a ejecutar antes de la queryDatabase resultado se coloca en la workQueue.
    • El JIT no debe hacer nada que modifica el comportamiento del programa. Si no es un bug. Pero yo creo que es mucho más probable que la mis-orden de las salidas ha de hacer con su registro de alguna manera. Una cosa que podrías intentar es crear una segunda ArrayBlockingQueue y llevar a cabo su función de registro para agregar las declaraciones de registro a la cola. Al final de thread2, tire todas las declaraciones de registro de salida de la cola de impresión y de ellos uno por uno. Esto debe de garantizar que la impresión en el orden en que ocurrieron. Yo no recomendaría esto a largo plazo, pero podría ser útil como prueba.

  2. 20

    La llamada a queryDatabase() que ocurra primero. A continuación, el bloque finally. A continuación, las hojas de control de la función (que es la return).

    • +1 para; indicándolo así en el orden de queryDatabase() que he omitido incluir en mi respuesta, ya que esto no era necesariamente lo que se les pide, y es bueno/interesante saber de todos modos.
    • Estoy de acuerdo con usted, usted puede probarlo a partir de la especificación?
    • No, No puedo! Yo no soy un experto.
    • La prueba de bloque también cubre la queryDataBase() llamada, por lo que esta llamada tiene que suceder antes de que la finally bloque.
    • eso es lo que mi respuesta dice
    • Sí, fue un boceto de una prueba. gcooney la tiene completa, así que no se repita.
    • gracias. Entiendo lo que quiso decir ahora.

  3. 3

    La finally cláusula deberá ejecutar no importa cuál es el resultado o comportamiento de la try bloque, por lo que el finally se ejecuta antes de que el return.

  4. 2

    Si usted está utilizando un solo hilo, usted debe ver «tenga+, fetch+, fetch, toma». En tu ejemplo, es multi-hilo, así que usted no está seguro de lo que ocurra primero.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea