Uwaga: Jeśli maszyna JVM zakończy działanie podczas wykonywania kodu try lub catch, blok final może nie zostać wykonany. Podobnie, jeśli wątek wykonujący kod try lub catch zostanie przerwany lub zabity, ostatni blok może nie zostać wykonany, nawet jeśli aplikacja jako całość będzie kontynuowana.
Nie znam innych sposobów, w jakie ostateczny blok nie zostałby wykonany ...
@dhiller - Jestem prawie pewien, że „wyłączanie zasilania” jest uwzględnione w sekcji „Jeśli JVM kończy pracę ...” :-p
Jason Coco
2
@Jason Coco: Zakończenie (jak w przypadku utraty zasilania) to nie to samo, co wyjście; ten drugi jest mniej lub bardziej zorganizowanym procesem, którego kulminacją jest ten pierwszy. ; p
user359996
2
AFAIK, jeśli wątek zostanie przerwany, nie jest natychmiast zatrzymywany. To do kodu w wątku należy wykrycie przerwania i zatrzymanie zadania, więc w końcu kod powinien zostać uruchomiony.
Bart van Heukelom
2
Myślę, że jeśli wyjątek zostanie zgłoszony w ostatnim bloku, reszta bloku nie zostanie wykonana.
Kończy aktualnie uruchomioną wirtualną maszynę Java. Argument służy jako kod statusu; Zgodnie z konwencją niezerowy kod statusu wskazuje na nieprawidłowe zakończenie.
Ta metoda wywołuje exitmetodę w klasie Runtime. Ta metoda nigdy nie zwraca normalnie.
Wyjątek powinien również spowodować zamknięcie wirtualnej maszyny języka Java.
Kaissun
3
Jeśli wyjątek wystąpi podczas wykonywania System.exit (0), to ostatecznie blok zostanie wykonany.
halil
50
Aby rozwinąć to, co powiedzieli inni, wszystko, co nie spowoduje czegoś takiego jak zamknięcie maszyny JVM, spowoduje ostateczną blokadę. Więc następująca metoda:
to naprawdę zdezorientowało mnie przez dobre kilka godzin kilka tygodni temu.
nickf
3
Zwracanie wartości z końcowego bloku jest uważane za zły pomysł. Powróć tylko z bloku try lub wróć spoza bloku try / final. Większość IDE zaznaczy to ostrzeżeniem.
Biegałem z Bironem
1
@nickf Rozumiem, że nie jesteś już zdezorientowany. Czy mógłbyś rozwinąć mechanikę, dlaczego zwracana jest 1, a nie 0. Mogę się tylko domyślać, że pamięć (lub jest to rejestr), która przechowuje wartość zwracaną przez funkcję, która początkowo zawiera 0, jest nadpisywana podczas wykonywania ostatniego bloku .
Yaneeve
2
To ciekawe, w C # nie można wrócić z końcowego bloku.
JMCF125
3
@RanBiron Oczywiście. W rzeczywistości nie zalecał powrotu wewnątrz bloku Final, starał się tylko zademonstrować, że nawet instrukcja return nadal spowoduje wykonanie kodu w tym bloku.
Aquarelle
15
W przypadku System.exit istnieją również pewne typy katastrofalnych awarii, w przypadku których ostateczna blokada może nie zostać wykonana. Jeśli JVM całkowicie zabraknie pamięci, może po prostu zakończyć działanie bez przechwytywania lub w końcu się dzieje.
W szczególności pamiętam projekt, w którym głupio próbowaliśmy wykorzystać
catch(OutOfMemoryError oome){// do stuff}
To nie zadziałało, ponieważ JVM nie miała pamięci na wykonanie bloku catch.
Kiedy wyrzucany jest OutOfMemoryError, zwykle pozostaje dużo pamięci (aby zatrzymać rzucanie GC). Jeśli jednak złapiesz go wielokrotnie, oczywiście wrócisz do rzucania w GC.
Tom Hawtin - tackline
Pomyślałem, że nie powinno się łapać niezaznaczonych wyjątków!
Sergii Shevchyk
1
Próbowałem po mojej stronie, używając jdk7, ale złapał błąd OutOfMemory!
Jaskey,
10
try{for(;;);}finally{System.err.println("?");}
W takim przypadku ostatecznie nie zostanie wykonany (chyba że Thread.stopzostanie wywołany przestarzały lub jego odpowiednik, powiedzmy, za pośrednictwem interfejsu narzędzi).
Nie sądzę, że jest jakiś haczyk. Być może wyobrażasz sobie haczyk, którego nie ma. Jeśli wstawimy jawne throw, finallyblok zostanie wykonany zgodnie z oczekiwaniami. try { throw new ThreadDeath(); } finally { System.err.println("?"); }
Tom Hawtin - tackline
9
Samouczek Sun został źle zacytowany w tym wątku.
Uwaga: Jeśli maszyna JVM zakończy działanie podczas wykonywania kodu try lub catch, blok final nie zostanie wykonany. Podobnie, jeśli wątek wykonujący kod try lub catch zostanie przerwany lub zabity, ostatni blok tak zrobi nie wykonany, nawet jeśli aplikacja jako całość będzie kontynuowana.
Jeśli przyjrzysz się uważnie samouczkowi Sun dla końcowego bloku, nie jest tam napisane "nie wykona", ale "może nie wykonać" Oto poprawny opis
Uwaga: Jeśli maszyna JVM zakończy działanie podczas wykonywania kodu try lub catch, blok final może nie zostać wykonany. Podobnie, jeśli wątek wykonujący kod try lub catch zostanie przerwany lub zabity, ostatni blok może nie zostać wykonany, nawet jeśli aplikacja jako całość będzie kontynuowana.
Oczywistym powodem takiego zachowania jest to, że wywołanie system.exit () jest przetwarzane w wątku systemowym środowiska wykonawczego, co może zająć trochę czasu, aby zamknąć jvm, w międzyczasie planista wątków może zażądać ostatecznego wykonania. Ostatecznie jest zaprojektowany tak, aby zawsze był wykonywany, ale jeśli zamykasz jvm, może się zdarzyć, że jvm zostanie zamknięty przed ostatecznym wykonaniem.
Technicznie rzecz biorąc, blok try nigdy nie wychodzi, więc ostatni blok nie powinien mieć szansy na wykonanie. To samo można powiedzieć o nieskończonej pętli.
Jeff Mercado,
6
Jeśli maszyna JVM zakończy działanie podczas wykonywania kodu try lub catch, blok final może nie zostać wykonany. ( źródło )
Normalne zamknięcie - dzieje się tak, gdy ostatni wątek niebędący demonem kończy działanie LUB gdy Runtime.exit () ( źródło )
Po zakończeniu wątku maszyna JVM przeprowadza inwentaryzację uruchomionych wątków, a jeśli jedynymi pozostałymi wątkami są wątki demonów, inicjuje uporządkowane zamknięcie. Kiedy JVM zatrzymuje się, wszystkie pozostałe wątki demona są porzucane, a wreszcie bloki nie są wykonywane, stosy nie są rozwijane, JVM po prostu kończy pracę. Wątki demona powinny być używane oszczędnie. Niewiele czynności przetwarzania można bezpiecznie porzucić w dowolnym momencie bez czyszczenia. W szczególności niebezpieczne jest używanie wątków demonów do zadań, które mogą wykonywać dowolne operacje we / wy. Wątki demona najlepiej zapisywać do zadań „porządkowych”, takich jak wątek w tle, który okresowo usuwa wygasłe wpisy z pamięci podręcznej w pamięci. ( źródło )
Przykład wyjścia ostatniego wątku niebędącego demonem:
publicclassTestDaemon{privatestaticRunnable runnable =newRunnable(){@Overridepublicvoid run(){try{while(true){System.out.println("Is alive");Thread.sleep(10);// throw new RuntimeException();}}catch(Throwable t){
t.printStackTrace();}finally{System.out.println("This will never be executed.");}}};publicstaticvoid main(String[] args)throwsInterruptedException{Thread daemon =newThread(runnable);
daemon.setDaemon(true);
daemon.start();Thread.sleep(100);// daemon.stop();System.out.println("Last non-daemon thread exits.");}}
Wynik:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.Is alive
Is alive
Is alive
Is alive
Is alive
Istnieją dwa sposoby, aby ostatecznie zatrzymać wykonywanie kodu blokowego:
1. Użyj System.exit ();
2. Jeśli w jakiś sposób kontrola wykonania nie osiągnie, spróbuj zablokować.
Widzieć:
publicclassMain{publicstaticvoid main (String[]args){if(true){System.out.println("will exceute");}else{try{System.out.println("result = "+5/0);}catch(ArithmeticException e){System.out.println("will not exceute");}finally{System.out.println("will not exceute");}}}}
Natknąłem się na bardzo specyficzny przypadek, w którym ostatni blok nie jest wykonywany, związany konkretnie z frameworkiem odtwarzania.
Zaskoczyło mnie, że ostatni blok w tym kodzie akcji kontrolera został wywołany tylko po wystąpieniu wyjątku, ale nigdy, gdy wywołanie faktycznie się powiodło.
try{InputStream is = getInputStreamMethod();
renderBinary(is,"out.zip");catch(Exception e){
e.printStackTrace();}finally{
cleanUp();}
Być może wątek jest zakończony lub coś innego, gdy zostanie wywołana funkcja renderBinary (). Podejrzewałbym, że to samo dzieje się z innymi wywołaniami render (), ale nie zweryfikowałem tego.
Rozwiązałem ten problem, przenosząc renderBinary () na koniec try / catch. Dalsze dochodzenie ujawniło, że gra udostępnia adnotację @Finally, aby utworzyć metodę, która jest wykonywana po wykonaniu akcji kontrolera. Zastrzeżenie polega na tym, że zostanie to wywołane po wykonaniu DOWOLNEJ akcji w kontrolerze, więc nie zawsze może to być dobry wybór.
//If ArithmeticException Occur Inner finally would not be executedclassTemp{publicstaticvoid main(String[] s){try{int x =10/s.length;System.out.println(x);try{int z[]=newint[s.length];
z[10]=1000;}catch(ArrayIndexOutOfBoundsException e){System.out.println(e);}finally{System.out.println("Inner finally");}}catch(ArithmeticException e){System.out.println(e);}finally{System.out.println("Outer Finally");}System.out.println("Remaining Code");}}
Odpowiedzi:
z samouczków Sun
Nie znam innych sposobów, w jakie ostateczny blok nie zostałby wykonany ...
źródło
System.exit wyłącza maszynę wirtualną.
„Do widzenia” nie jest drukowane w powyższym kodzie.
źródło
Aby rozwinąć to, co powiedzieli inni, wszystko, co nie spowoduje czegoś takiego jak zamknięcie maszyny JVM, spowoduje ostateczną blokadę. Więc następująca metoda:
będzie dziwnie kompilować i zwracać 1.
źródło
W przypadku System.exit istnieją również pewne typy katastrofalnych awarii, w przypadku których ostateczna blokada może nie zostać wykonana. Jeśli JVM całkowicie zabraknie pamięci, może po prostu zakończyć działanie bez przechwytywania lub w końcu się dzieje.
W szczególności pamiętam projekt, w którym głupio próbowaliśmy wykorzystać
To nie zadziałało, ponieważ JVM nie miała pamięci na wykonanie bloku catch.
źródło
W takim przypadku ostatecznie nie zostanie wykonany (chyba że
Thread.stop
zostanie wywołany przestarzały lub jego odpowiednik, powiedzmy, za pośrednictwem interfejsu narzędzi).źródło
throw
,finally
blok zostanie wykonany zgodnie z oczekiwaniami.try { throw new ThreadDeath(); } finally { System.err.println("?"); }
Samouczek Sun został źle zacytowany w tym wątku.
Uwaga: Jeśli maszyna JVM zakończy działanie podczas wykonywania kodu try lub catch, blok final nie zostanie wykonany. Podobnie, jeśli wątek wykonujący kod try lub catch zostanie przerwany lub zabity, ostatni blok tak zrobi nie wykonany, nawet jeśli aplikacja jako całość będzie kontynuowana.
Jeśli przyjrzysz się uważnie samouczkowi Sun dla końcowego bloku, nie jest tam napisane "nie wykona", ale "może nie wykonać" Oto poprawny opis
Oczywistym powodem takiego zachowania jest to, że wywołanie system.exit () jest przetwarzane w wątku systemowym środowiska wykonawczego, co może zająć trochę czasu, aby zamknąć jvm, w międzyczasie planista wątków może zażądać ostatecznego wykonania. Ostatecznie jest zaprojektowany tak, aby zawsze był wykonywany, ale jeśli zamykasz jvm, może się zdarzyć, że jvm zostanie zamknięty przed ostatecznym wykonaniem.
źródło
Również wtedy, gdy w środku zdarzy się zakleszczenie / żywa żywa ryba
try
.Oto kod, który to demonstruje:
Ten kod generuje następujące dane wyjściowe:
a „w końcu” nigdy nie jest drukowane
źródło
Jeśli maszyna JVM zakończy działanie podczas wykonywania kodu try lub catch, blok final może nie zostać wykonany. ( źródło )
Normalne zamknięcie - dzieje się tak, gdy ostatni wątek niebędący demonem kończy działanie LUB gdy Runtime.exit () ( źródło )
Po zakończeniu wątku maszyna JVM przeprowadza inwentaryzację uruchomionych wątków, a jeśli jedynymi pozostałymi wątkami są wątki demonów, inicjuje uporządkowane zamknięcie. Kiedy JVM zatrzymuje się, wszystkie pozostałe wątki demona są porzucane, a wreszcie bloki nie są wykonywane, stosy nie są rozwijane, JVM po prostu kończy pracę. Wątki demona powinny być używane oszczędnie. Niewiele czynności przetwarzania można bezpiecznie porzucić w dowolnym momencie bez czyszczenia. W szczególności niebezpieczne jest używanie wątków demonów do zadań, które mogą wykonywać dowolne operacje we / wy. Wątki demona najlepiej zapisywać do zadań „porządkowych”, takich jak wątek w tle, który okresowo usuwa wygasłe wpisy z pamięci podręcznej w pamięci. ( źródło )
Przykład wyjścia ostatniego wątku niebędącego demonem:
Wynik:
źródło
W następujących przypadkach ostateczny blok nie zostanie wykonany: -
System.exit(0)
jest wywoływana ztry
bloku.try
blokuMogą również istnieć inne skrajne przypadki, w których ostatecznie blok nie zostanie wykonany.
źródło
Istnieją dwa sposoby, aby ostatecznie zatrzymać wykonywanie kodu blokowego:
1. Użyj System.exit ();
2. Jeśli w jakiś sposób kontrola wykonania nie osiągnie, spróbuj zablokować.
Widzieć:
źródło
Natknąłem się na bardzo specyficzny przypadek, w którym ostatni blok nie jest wykonywany, związany konkretnie z frameworkiem odtwarzania.
Zaskoczyło mnie, że ostatni blok w tym kodzie akcji kontrolera został wywołany tylko po wystąpieniu wyjątku, ale nigdy, gdy wywołanie faktycznie się powiodło.
Być może wątek jest zakończony lub coś innego, gdy zostanie wywołana funkcja renderBinary (). Podejrzewałbym, że to samo dzieje się z innymi wywołaniami render (), ale nie zweryfikowałem tego.
Rozwiązałem ten problem, przenosząc renderBinary () na koniec try / catch. Dalsze dochodzenie ujawniło, że gra udostępnia adnotację @Finally, aby utworzyć metodę, która jest wykonywana po wykonaniu akcji kontrolera. Zastrzeżenie polega na tym, że zostanie to wywołane po wykonaniu DOWOLNEJ akcji w kontrolerze, więc nie zawsze może to być dobry wybór.
źródło
źródło