Czy jest jakiś warunek, w którym ostatecznie może nie działać w Javie? Dzięki.
Czy jest jakiś warunek, w którym ostatecznie może nie działać w Javie? Dzięki.
Odpowiedzi:
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 ...
System.exit wyłącza maszynę wirtualną.
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
exit
metodę w klasieRuntime
. Ta metoda nigdy nie zwraca normalnie.
try {
System.out.println("hello");
System.exit(0);
}
finally {
System.out.println("bye");
} // try-finally
„Do widzenia” nie jest drukowane w powyższym kodzie.
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:
public static int Stupid() {
try {
return 0;
}
finally {
return 1;
}
}
będzie dziwnie kompilować i zwracać 1.
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.
try { for (;;); } finally { System.err.println("?"); }
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).
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
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.
Również wtedy, gdy w środku zdarzy się zakleszczenie / żywa żywa ryba try
.
Oto kod, który to demonstruje:
public class DeadLocker {
private static class SampleRunnable implements Runnable {
private String threadId;
private Object lock1;
private Object lock2;
public SampleRunnable(String threadId, Object lock1, Object lock2) {
super();
this.threadId = threadId;
this.lock1 = lock1;
this.lock2 = lock2;
}
@Override
public void run() {
try {
synchronized (lock1) {
System.out.println(threadId + " inside lock1");
Thread.sleep(1000);
synchronized (lock2) {
System.out.println(threadId + " inside lock2");
}
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
public static void main(String[] args) throws Exception {
Object ob1 = new Object();
Object ob2 = new Object();
Thread t1 = new Thread(new SampleRunnable("t1", ob1, ob2));
Thread t2 = new Thread(new SampleRunnable("t2", ob2, ob1));
t1.start();
t2.start();
}
}
Ten kod generuje następujące dane wyjściowe:
t1 inside lock1
t2 inside lock1
a „w końcu” nigdy nie jest drukowane
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:
public class TestDaemon {
private static Runnable runnable = new Runnable() {
@Override
public void 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.");
}
}
};
public static void main(String[] args) throws InterruptedException {
Thread daemon = new Thread(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
W następujących przypadkach ostateczny blok nie zostanie wykonany: -
System.exit(0)
jest wywoływana z try
bloku. try
bloku Mogą również istnieć inne skrajne przypadki, w których ostatecznie blok nie zostanie wykonany.
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ć:
public class Main
{
public static void 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 executed
class Temp
{
public static void main(String[] s)
{
try
{
int x = 10/s.length;
System.out.println(x);
try
{
int z[] = new int[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");
}
}