2010-04-28 16 views
5

Diese Frage nagt mich für eine Weile, aber ich habe noch keine vollständige Antwort gefunden (z. B. dieses ist für C# Initializing disposable resources outside or inside try/finally). Betrachten wir zwei folgenden Java-Code-Fragmente:Java versuchen schließlich Variationen

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

und zweite Variation

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

Der Teil, der mir Sorgen macht, ist, dass der Faden könnte etwas zwischen dem Moment Ressource unterbrochen werden erfasst (zB Datei geöffnet ist) Der resultierende Wert wird jedoch nicht der jeweiligen lokalen Variablen zugewiesen. Gibt es noch andere Szenarien der Faden könnte als über andere in dem Punkt unterbrochen werden:

  1. InterruptedException (zB über Thread # Interrupt()) oder OutOfMemoryError Ausnahme ausgelöst
  2. JVM-Exits (zB über töten, System. exit())
  3. Hardware fehlschlagen (oder Fehler in JVM für eine vollständige Liste :)

ich gelesen habe, dass der zweite Ansatz etwas mehr „idiomatische“ ist aber IMO in dem obigen Szenario gibt es keinen Unterschied und in allen anderen Szenarien sind sie gleich.

So ist die Frage:

Was sind die Unterschiede zwischen den beiden sind? Was sollte ich bevorzugen, wenn ich Bedenken bezüglich der Ressourcenfreigabe habe (besonders in stark multi-threading Anwendungen)? Warum?

Ich würde mich freuen, wenn mich jemand auf Teile von Java/JVM-Spezifikationen verweist, die die Antworten unterstützen.

Antwort

6

Ich glaube nicht, dass es einen Grund, besorgt zu sein:

1) InterruptedException (zB über Thread # Interrupt())

Der Aufruf Thread.interrupt() führt nicht dazu, dass InterruptedException spontan ausgelöst wird. Die Ausnahme wird nur innerhalb bestimmter (und gut dokumentierter) Blockierungsmethoden ausgelöst. d.h. blockierende I/O- und Synchronisationsverfahren. Diese Ausnahme kann nicht ausgelöst werden, nachdem sie vom Stream-Konstruktor zurückgegeben wurde und bevor der try-Block eingegeben wurde.

oder OutOfMemoryError Ausnahme

geworfen

Wenn ein OutOfMemoryError geworfen wird, kann man nicht vollständige Erholung des zugrunde liegenden Dateideskriptors garantieren, egal wo Sie den Stream Konstruktor setzen. Sie sollten nie versuchen, von einem OOM wiederherzustellen, daher ist die Frage, ob der Stream geschlossen ist, strittig. Außerdem wird diese Ausnahme nur auf einen Thread geworfen, der tatsächlich versucht, Speicher zuzuweisen, und das ist zu diesem Zeitpunkt nicht der Fall.

2) JVM-Exits (zB über töten, System.exit())

Wenn die Anwendung gewaltsam von einer externen kill oder einen System.exit() Anruf beendet ist, spielt es keine Rolle, ob Ströme richtig geschlossen. Außerdem gibt es in beiden Fällen keine Garantie, dass die Endgültigkeitsklauseln ausgeführt werden.

3) Hardware fehlschlagen (oder Fehler in JVM für eine vollständige Liste :)

Alle Wetten ausgeschaltet sind. Sie haben keine Möglichkeit zu wissen, ob etwas ausgeführt wird, geschweige denn die endgültigen Blöcke.

Es gibt noch eine weitere Situation, in der ein Thread zu diesem Zeitpunkt eine spontane Ausnahme mit einer (naiven) Erwartung erhalten könnte, dass er sich erholen könnte. Das ist, wenn ein fehlgeleiteter Programmierer beschließt, die veraltete Methode Thread.stop() aufzurufen. Sie könnten denken, dass es hilfreich wäre, den Aufruf des Stream-Konstruktors in den Block try zu setzen. Aber eigentlich wird es nicht, weil die ThreadDeath Ausnahme innerhalb der Stream-Konstruktor zwischen dem Öffnen der zugrunde liegenden Datei und Abschluss der Konstruktion des Stream-Objekts ausgelöst werden kann. So könnte der FD trotzdem auslaufen.

Dies ist nur ein Grund, warum Thread.stop() veraltet ist. Benutze es nicht.

0

Meine Ansicht ist, dass wenn Sie mit einer verwalteten Laufzeit wie Java oder .NET arbeiten, sollten Sie nicht wirklich (und es ist gut!) Sich mit Dingen wie Ihrer speziellen Frage beschäftigen. Nur weil Sie vollständig vom zugrunde liegenden Betriebssystem und seinen systemeigenen APIs getrennt sind. Alles, was Sie wissen müssen, ist, dass Sie Closable.close() in Ihrem finally Block aufrufen und Ihre Ressource wird immer freigegeben werden.

+0

solange Sie die Ressource im try-Block erworben haben ... – pgras

+0

Leider bedeutet "verwaltet", dass es nur einen Teil der Probleme der Ressourcenverwaltung löst (wenn auch eine beträchtliche). Wenn Sie viele Ressourcen erwerben, sollten Sie immer noch darauf achten, sie zu veröffentlichen, da es in der Regel eine begrenzte Menge von ihnen gibt. Und ja, da sind Schlösser. Und Deadlocks. –

+0

@pgras Warum möchten Sie die Ressourcen im 'try' Block erwerben? Das macht nur einen Fehler in Ihrem Code. –

5

a) Beachten Sie, dass das Unterbrechen des Threads mit interrupt() nicht sofort wirksam wird und überhaupt keine Wirkung hat, wenn der unterbrochene Thread nicht kooperiert. Es gibt keine Möglichkeit der Faden aufgrund verlassen wird von() während der Ausführung zu unterbrechen:

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

Das einzige, was passieren wird, ist, dass seine unterbrochen Flagge des Fadens wird eingeschaltet.

b) in Bezug auf OutOfMemoryError - Ich sehe nicht, wie es direkt nach der Konstruktion des Eingabestroms auftreten kann. Es kann in einem anderen Thread auftreten, aber dies hat keine unmittelbare Auswirkung auf diesen Thread. Das Problem mit OutOfMemoryError ist, dass Ihr finally-Block möglicherweise auch fehlschlägt, weil nicht genügend Speicher vorhanden ist, um den Vorgang abzuschließen ...

c) Der einzige Weg, wie ich weiß, dass ein Thread aggressiv unterbrochen werden kann, ist der veraltete Methoden-Thread .stop() und Thread.stop (Throwable). Siehe eine ähnliche Diskussion hier: Is this a safe way to release resources in Java?

Verwandte Themen