6 Stimmen

Java versuchen schließlich Variationen

Diese Frage quält mich schon eine Weile, aber ich habe noch keine vollständige Antwort darauf gefunden (z.B. diese hier ist für C# Initialisierung verfügbarer Ressourcen außerhalb oder innerhalb von try/finally ). Betrachten Sie die beiden folgenden Java-Codefragmente:

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

und die zweite Variante

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

Der Teil, der mich beunruhigt, ist, dass der Thread etwas zwischen dem Moment unterbrochen werden könnte, Ressource erworben wird (z. B. Datei geöffnet wird), aber resultierende Wert wird nicht an entsprechende lokale Variable zugewiesen. Gibt es andere Szenarien, die der Thread im obigen Punkt unterbrochen werden könnte, außer:

  1. InterruptedException (z. B. über Thread#interrupt()) oder OutOfMemoryError-Ausnahme ausgelöst wird
  2. Beenden der JVM (z. B. über kill, System.exit())
  3. Hardwarefehler (oder Fehler in der JVM für eine vollständige Liste :)

Ich habe gelesen, dass der zweite Ansatz etwas "idiomatischer" ist, aber IMO gibt es in dem obigen Szenario keinen Unterschied und in allen anderen Szenarien sind sie gleich.

Daher die Frage:

Was sind die Unterschiede zwischen den beiden? Welcher sollte ich den Vorzug geben, wenn ich mir Gedanken über das Freigeben von Ressourcen mache (insbesondere bei stark multi-threading-fähigen Anwendungen)? Und warum?

Ich wäre dankbar, wenn mir jemand Hinweise auf Teile der Java/JVM-Spezifikationen geben könnte, die die Antworten unterstützen.

6voto

Stephen C Punkte 665668

Ich glaube nicht, dass es einen Grund gibt, sich Sorgen zu machen:

1) InterruptedException (z. B. über Thread#interrupt())

Aufruf von Thread.interrupt() verursacht keine InterruptedException spontan geworfen werden. Die Ausnahme wird nur innerhalb bestimmter (und gut dokumentierter) blockierender Methoden ausgelöst, d. h. blockierender E/A- und Synchronisierungsmethoden. Diese Ausnahme kann nicht nach der Rückkehr vom Stream-Konstruktor und vor dem Eintritt in den Try-Block ausgelöst werden.

oder eine OutOfMemoryError-Ausnahme ausgelöst wird

Wenn ein OutOfMemoryError ausgelöst wird, können Sie nicht garantieren, dass der zugrunde liegende Dateideskriptor vollständig wiederhergestellt werden kann, unabhängig davon, wo Sie den Stream-Konstruktor platzieren. Sie sollten niemals versuchen, sich von einem OOM zu erholen, so dass die Frage, ob der Stream geschlossen ist, überflüssig ist. Außerdem wird diese Ausnahme nur bei einem Thread ausgelöst, der gerade versucht, Speicher zuzuweisen, und das ist zu diesem Zeitpunkt nicht der Fall.

2) JVM wird beendet (z. B. über kill, System.exit())

Wenn die Anwendung durch ein externes Ereignis zwangsweise beendet wird kill o un System.exit() aufrufen, spielt es keine Rolle, ob die Streams ordnungsgemäß geschlossen sind. Außerdem gibt es in beiden Fällen keine Garantie, dass die finally-Klauseln ausgeführt werden.

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

Alle Wetten sind aufgehoben. Sie können nicht wissen, ob irgendetwas ausgeführt wird, geschweige denn, welche Blöcke letztendlich ausgeführt werden.

Es gibt noch eine weitere Situation, in der ein Thread zu diesem Zeitpunkt eine spontane Ausnahme erhalten könnte, in der (naiven) Erwartung, dass er sich wieder erholen könnte. Das ist der Fall, wenn ein fehlgeleiteter Programmierer beschließt, das veraltete Thread.stop() Methode. Man könnte meinen, dass der Aufruf des Stream-Konstruktors innerhalb der try Block helfen würde. Aber das wird es nicht, denn die ThreadDeath könnte eine Ausnahme ausgelöst werden innerhalb der Stream-Konstruktor zwischen dem Öffnen der zugrunde liegenden Datei und dem Abschluss der Konstruktion des Stream-Objekts. Der FD könnte also trotzdem undicht werden.

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

5voto

Eyal Schneider Punkte 21626

A) Beachten Sie, dass die Unterbrechung des Threads mit interrupt() nicht sofort wirksam wird und möglicherweise überhaupt keinen Effekt hat, wenn der unterbrochene Thread nicht kooperiert. Es gibt keine Möglichkeit, dass der Thread aufgrund von interrupt() während der Ausführung von :

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

Das Einzige, was passieren wird, ist, dass das Flag des unterbrochenen Threads aktiviert wird.

b) in Bezug auf OutOfMemoryError - ich sehe nicht, wie er direkt nach der Erstellung des Eingabestroms auftreten kann. Er kann in einem anderen Thread auftreten, aber das hat keine unmittelbaren Auswirkungen auf diesen Thread. Das Problem mit OutOfMemoryError ist, dass Ihr finally-Block auch fehlschlagen kann, weil nicht genug Speicher vorhanden ist, um ihn abzuschließen...

c) Die einzige mir bekannte Möglichkeit, einen Thread aggressiv zu unterbrechen, ist die Verwendung der veralteten Methoden Thread.stop() und Thread.stop(Throwable). Siehe eine ähnliche Diskussion hier: Ist dies ein sicherer Weg, um Ressourcen in Java freizugeben?

0voto

Strelok Punkte 47933

Wenn Sie mit einer verwalteten Laufzeitumgebung wie Java oder .NET arbeiten, sollten Sie sich meiner Meinung nach wirklich nicht (und das ist gut so!) mit Dingen wie Ihrer speziellen Frage beschäftigen. Nur weil Sie vom zugrunde liegenden Betriebssystem und seinen nativen APIs völlig abgekoppelt sind. Alles, was Sie wissen müssen, ist, dass Sie Closable.close() en su finally Block und Ihre Ressource wird immer freigegeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X