2010-04-28 14 views
5

Esta pregunta me fastidia por un tiempo pero aún no encontré una respuesta completa (por ejemplo, esta es para C# Initializing disposable resources outside or inside try/finally). Considere dos siguientes fragmentos de código Java:Java try finally variations

Closeable in = new FileInputStream("data.txt"); 
try { 
    doSomething(in); 
} finally { 
    in.close(); 
} 

y la segunda variación

Closeable in = null; 
try { 
    in = new FileInputStream("data.txt"); 
    doSomething(in); 
} finally { 
    if (null != in) in.close(); 
} 

La parte que me preocupa es que el hilo podría ser interrumpido algo entre el recurso momento en que se adquiere (por ejemplo archivo se abre) pero el valor resultante no está asignado a la variable local respectiva. ¿Hay alguna otra escenarios del hilo podría ser interrumpido en el punto anterior que no sea:

  1. InterruptedException (por ejemplo a través del hilo # interrupción()) o OutOfMemoryError excepción es lanzada
  2. salidas de JVM (por ejemplo, a través de matar, Sistema. exit())
  3. hardware falla (o error en la JVM para la lista completa :)

he leído que el segundo enfoque es algo más "idiomática", pero la OMI en el escenario anterior no hay diferencia y en todos los demás escenarios son iguales.

Entonces la pregunta:

¿Cuáles son las diferencias entre los dos? ¿Qué debería preferir si me preocupo por la liberación de recursos (especialmente en aplicaciones con varios subprocesos)? ¿Por qué?

Agradecería que alguien me señale las partes de las especificaciones de Java/JVM que respaldan las respuestas.

Respuesta

6

No creo que haya ninguna razón para preocuparse:

1) InterruptedException (por ejemplo a través del hilo # interrupción())

Llamar al Thread.interrupt() no provoca que InterruptedException se arroje espontáneamente. La excepción solo se produce dentro de métodos de bloqueo específicos (y bien documentados); es decir, bloqueo de E/S y métodos de sincronización. Esta excepción no se puede lanzar después de regresar del constructor de la secuencia y antes de ingresar al bloque try.

o OutOfMemoryError excepción es lanzada

Si un OutOfMemoryError se lanza, no se puede garantizar la recuperación total del descriptor de archivos subyacente, sin importar dónde se pone el constructor de flujo. Nunca debe intentar recuperarse de un OOM, por lo que la cuestión de si el flujo está cerrado es discutible. Además, esta excepción solo se produce en un hilo que realmente intenta asignar memoria, y eso no sucede en este punto.

salidas 2) JVM (por ejemplo, a través de matar, System.exit())

Si la aplicación se está poniendo fin a la fuerza por un kill externa o una llamada System.exit(), no importa si son corrientes cerrado correctamente. Además, en ambos casos no hay garantía de que finalmente se ejecutarán las cláusulas.

3) Hardware fallan (o error en la JVM para la lista completa :)

Todas las apuestas están apagadas. No tienes forma de saber si algo se ejecutará, y mucho menos los bloques finales.

Hay una situación más donde un hilo puede recibir una excepción espontánea en ese punto, con alguna expectativa (ingenua) de que pueda recuperarse. Es entonces cuando un programador equivocado decide llamar al método obsoleto Thread.stop(). Puede pensar que poner la llamada de constructor de flujo dentro del bloque try ayudaría. Pero en realidad no lo hará, porque la excepción ThreadDeath podría aumentarse dentro de constructor de la secuencia entre abrir el archivo subyacente y completar la construcción del objeto de secuencia. Entonces el FD podría filtrarse de todos modos.

Esta es solo una razón por la cual Thread.stop() está en desuso. No lo uses

0

Mi opinión es que cuando trabajas con un tiempo de ejecución administrado, como Java o .NET, no deberías (¡y es bueno!) Preocuparte por cuestiones como tu pregunta en particular. Solo porque está completamente desconectado del sistema operativo subyacente y sus API nativas. Todo lo que debe saber es que llama al Closable.close() en su bloque finally y su recurso siempre será liberado.

+0

siempre que haya adquirido el recurso en el bloque try ... – pgras

+0

Desafortunadamente, "administrado" significa que resuelve solo una parte de los problemas de administración de recursos (aunque es considerable). Si adquiere muchos recursos, debe tener cuidado de liberarlos, ya que generalmente hay una cantidad limitada de ellos. Y sí, hay bloqueos. Y bloqueos. –

+0

@pgras ¿Por qué querrías adquirir los recursos en el bloque 'try'? Eso solo arruina tu código. –

5

a) Tenga en cuenta que la interrupción del hilo con la interrupción() no tendrá efecto inmediatamente, y puede no tener ningún efecto en absoluto, si el hilo que se está interrumpiendo no coopera. No hay manera de salir de la rosca se debe interrumpir() durante la ejecución de:

Closeable in = new FileInputStream("data.txt"); 

El único que va a pasar es que se convirtió en su bandera interrumpido de la rosca.

b) con respecto a OutOfMemoryError - No veo cómo puede ocurrir inmediatamente después de la construcción de la secuencia de entrada. Puede ocurrir en otro hilo, pero esto no tendrá un efecto inmediato en este hilo. El problema con OutOfMemoryError es que su bloque finally también puede fallar, porque no hay suficiente memoria para completarlo ...

c) La única forma en que sé que un hilo se puede interrumpir agresivamente es usar los métodos obsoletos. .stop() y Thread.stop (Throwable).Ver una discusión similar aquí: Is this a safe way to release resources in Java?

Cuestiones relacionadas