Apakah pemblokiran akhirnya selalu berjalan?


112

Apakah ada kondisi dimana akhirnya tidak bisa berjalan di java? Terima kasih.


13
Apakah ini pertanyaan yang mungkin Anda tanyakan ketika mencoba mendapatkan pekerjaan di perusahaan terkenal tertentu?
Tom Hawtin - tackline

@ TomHawtin-tackline Mau menamainya? (Tuhan, saya merindukan berapa umur posting ini!)
Hele

6
@Hele Saya tidak ingin memberikan game itu begitu saja, tapi Anda bisa google.
Tom Hawtin - tackline

jawaban singkatnya: ya, dalam kondisi normal.
Hiu

Jawaban:


139

dari Sun Tutorials

Catatan: Jika JVM keluar saat kode coba atau tangkap sedang dijalankan, maka blok terakhir mungkin tidak dapat dijalankan. Demikian juga, jika utas yang menjalankan kode coba atau tangkap diinterupsi atau dimatikan, blok terakhir mungkin tidak dijalankan meskipun aplikasi secara keseluruhan berlanjut.

Saya tidak tahu cara lain yang akhirnya blok tidak akan dieksekusi ...


6
@dhiller - Saya cukup yakin bahwa "power down" disertakan dalam "Jika JVM keluar ..." :-p
Jason Coco

2
@Jason Coco: Menghentikan (karena kehilangan kekuasaan) tidak sama dengan keluar; yang terakhir adalah proses yang kurang lebih terorganisir yang berpuncak pada yang pertama. ; p
pengguna359996

2
AFAIK, jika utas terputus, itu tidak segera dihentikan. Terserah kode di utas untuk mendeteksi gangguan dan menghentikan tugasnya, jadi akhirnya kode harus dijalankan.
Bart van Heukelom

2
Saya rasa jika pengecualian dilemparkan di blok akhirnya, blok lainnya tidak akan dieksekusi.
Adriaan Koster

baik itu menyebalkan!
eiran

63

System.exit mematikan Mesin Virtual.

Menghentikan Java Virtual Machine yang sedang berjalan. Argumen berfungsi sebagai kode status; menurut kesepakatan, kode status bukan nol menunjukkan penghentian abnormal.

Metode ini memanggil exitmetode di kelas Runtime. Metode ini tidak pernah kembali secara normal.

    try {
        System.out.println("hello");
        System.exit(0);
    }
    finally {
        System.out.println("bye");
    } // try-finally

"bye" tidak dicetak dalam kode di atas.


Juga pengecualian harus mematikan Mesin Virtual Java.
kaissun

3
Jika Exception terjadi saat menjalankan System.exit (0), maka akhirnya blok akan dijalankan.
halil

50

Hanya untuk memperluas apa yang orang lain katakan, apa pun yang tidak menyebabkan sesuatu seperti keluarnya JVM akan menyebabkan pemblokiran terakhir. Jadi caranya berikut ini:

public static int Stupid() {
  try {
    return 0;
  }
  finally {
    return 1;
  }
}

anehnya akan mengkompilasi dan mengembalikan 1.


2
ini benar-benar membuatku bingung selama beberapa jam beberapa minggu yang lalu.
nickf

3
Mengembalikan nilai dari blok terakhir dianggap sebagai ide yang buruk. Baik kembali hanya dari blok percobaan, atau kembali dari luar blok percobaan / akhirnya. Kebanyakan IDE akan menandai ini dengan sebuah peringatan.
Ran Biron

1
@nickf Saya rasa Anda tidak lagi bingung. Bisakah Anda menguraikan mekanisme mengapa 1 dikembalikan dan bukan 0. Saya hanya bisa menebak bahwa memori (atau apakah itu register) yang menyimpan nilai kembali dari fungsi yang awalnya memegang 0, ditimpa saat blok akhirnya dieksekusi .
Yaneeve

2
Aneh, di C # tidak diizinkan untuk kembali dari blok terakhir.
JMCF125

3
@RanBiron Tentu saja. Dia sebenarnya tidak merekomendasikan untuk kembali ke dalam blok terakhir, dia hanya mencoba untuk menunjukkan bahwa bahkan pernyataan kembali masih akan menyebabkan kode dalam blok tersebut untuk dieksekusi.
Aquarelle

15

Terkait dengan System.exit, ada juga jenis kegagalan katastropik tertentu di mana blok terakhir tidak dapat dijalankan. Jika JVM kehabisan memori seluruhnya, mungkin JVM keluar begitu saja tanpa tangkapan atau akhirnya terjadi.

Secara khusus, saya ingat sebuah proyek di mana kami dengan bodohnya mencoba menggunakannya

catch (OutOfMemoryError oome) {
    // do stuff
}

Ini tidak berhasil karena JVM tidak memiliki memori tersisa untuk mengeksekusi blok catch.


Saat OutOfMemoryError dilempar biasanya ada banyak memori yang tersisa (untuk menghentikan GC meronta-ronta). Namun, jika Anda menangkapnya berulang kali, Anda jelas akan kembali ke GC meronta-ronta.
Tom Hawtin - tackline

Saya pikir seseorang seharusnya tidak menangkap pengecualian yang tidak dicentang!
Sergii Shevchyk

1
Saya mencoba di sisi saya, menggunakan jdk7, tetapi itu menangkap Kesalahan OutOfMemory!
Jaskey

10
try { for (;;); } finally { System.err.println("?"); }

Dalam hal ini, akhirnya tidak akan dijalankan (kecuali deprecated Thread.stopdipanggil, atau yang setara, katakanlah, melalui antarmuka alat).


Halaman ini mengklaim bahwa kesalahan ThreadDeath terjadi, dan tumpukan terlepas secara normal saat Thread.stop () dipanggil. Apakah ada tangkapan yang saya lewatkan? download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/guide/…
spurserh

Saya tidak berpikir ada tangkapan. Mungkin di sana Anda membayangkan tangkapan yang tidak ada. Jika kita masukkan secara eksplisit throw, maka finallyblok tersebut akan dieksekusi seperti yang diharapkan. try { throw new ThreadDeath(); } finally { System.err.println("?"); }
Tom Hawtin - tackline

9

Tutorial Sun salah dikutip di sini di utas ini.

Catatan: Jika JVM keluar saat kode coba atau tangkap sedang dijalankan, maka blok terakhir tidak akan dijalankan. Demikian juga, jika thread yang menjalankan kode coba atau tangkap diinterupsi atau dimatikan, blok terakhir tidak akan dijalankan meskipun aplikasi secara keseluruhan berlanjut.

Jika Anda melihat tutorial sun lebih dekat untuk akhirnya memblokir, itu tidak mengatakan "tidak akan mengeksekusi" tetapi "mungkin tidak mengeksekusi" Berikut adalah deskripsi yang benar

Catatan: Jika JVM keluar saat kode coba atau tangkap sedang dijalankan, maka blok terakhir mungkin tidak dapat dijalankan. Demikian juga, jika utas yang menjalankan kode coba atau tangkap diinterupsi atau dimatikan, blok terakhir mungkin tidak dijalankan meskipun aplikasi secara keseluruhan berlanjut.

Alasan yang jelas untuk perilaku ini adalah, panggilan ke system.exit () diproses dalam thread sistem runtime yang mungkin memerlukan waktu untuk mematikan jvm, sementara penjadwal thread akhirnya dapat meminta untuk dieksekusi. Jadi akhirnya dirancang untuk selalu mengeksekusi, tetapi jika Anda mematikan jvm, mungkin saja jvm dimatikan sebelum akhirnya dieksekusi.


6

Juga jika terjadi deadlock / livelock di dalam tryblok.

Inilah kode yang mendemonstrasikannya:

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();
    }
}

Kode ini menghasilkan keluaran sebagai berikut:

t1 inside lock1
t2 inside lock1

dan "akhirnya" tidak pernah dicetak


3
Secara teknis, blok percobaan tidak pernah keluar sehingga blok terakhir seharusnya tidak pernah mendapat kesempatan untuk dieksekusi. Hal yang sama dapat dikatakan untuk putaran tak terbatas.
Jeff Mercado

6

Jika JVM keluar saat kode coba atau tangkap sedang dijalankan, maka blok terakhir tidak dapat dijalankan. ( sumber )

Normal Shutdown - ini terjadi baik ketika utas non-daemon terakhir keluar ATAU ketika Runtime.exit () ( sumber )

Ketika sebuah thread keluar, JVM melakukan inventarisasi thread yang sedang berjalan, dan jika satu-satunya thread yang tersisa adalah thread daemon, JVM memulai penghentian secara tertib. Saat JVM berhenti, setiap utas daemon yang tersisa ditinggalkan akhirnya blok tidak dieksekusi, tumpukan tidak dibatalkan, JVM baru saja keluar. Untaian daemon harus digunakan dengan hemat, beberapa aktivitas pemrosesan dapat ditinggalkan dengan aman kapan saja tanpa pembersihan. Secara khusus, berbahaya menggunakan utas daemon untuk tugas-tugas yang mungkin melakukan segala jenis I / O. Untaian daemon paling baik disimpan untuk tugas "rumah tangga", seperti utas latar belakang yang secara berkala menghapus entri kadaluwarsa dari cache dalam memori. ( sumber )

Contoh keluar utas non-daemon terakhir:

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.");
    }
}

Keluaran:

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

1

Dalam kasus berikut, akhirnya blok tidak akan dijalankan: -

  • Kapan System.exit(0)dipanggil dari tryblok.
  • Saat JVM kehabisan memori
  • Ketika proses java Anda mati paksa dari task mgr atau konsol
  • Kondisi deadlock di tryblok Anda
  • Saat mesin Anda mati karena listrik mati

Mungkin juga ada kasus pinggiran lainnya, di mana blokir akhirnya tidak akan dieksekusi.


1

Ada dua cara untuk menghentikan eksekusi kode blok:
1. Gunakan System.exit ();
2. Jika entah bagaimana kendali eksekusi tidak mencapai blok percobaan.
Lihat:

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");  
        }
    }
  }
}

0

Saya telah menemukan kasus yang sangat spesifik dari blok terakhir yang tidak mengeksekusi terkait secara khusus dengan kerangka bermain.

Saya terkejut menemukan bahwa blok terakhir dalam kode aksi pengontrol ini hanya dipanggil setelah Pengecualian, tetapi tidak pernah ketika panggilan benar-benar berhasil.

try {
    InputStream is = getInputStreamMethod();
    renderBinary(is, "out.zip");
catch (Exception e) {
    e.printStackTrace();
} finally {
    cleanUp();
}

Mungkin utas dihentikan atau sesuatu ketika renderBinary () dipanggil. Saya akan curiga hal yang sama terjadi untuk panggilan render () lainnya, tetapi saya tidak memverifikasinya.

Saya memecahkan masalah dengan memindahkan renderBinary () ke setelah coba / tangkap. Penyelidikan lebih lanjut mengungkapkan bahwa play menyediakan anotasi @Finally untuk membuat metode yang dijalankan setelah tindakan pengontrol dijalankan. Peringatan di sini adalah bahwa ini akan dipanggil setelah eksekusi tindakan APA PUN di pengontrol, jadi ini mungkin tidak selalu menjadi pilihan yang baik.


-1
//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");   
}
}

Perbaiki indentasi dan tambahkan beberapa detail.
ROMANIA_engineer

1
Eksekusinya bahkan tidak akan sampai ke blok percobaan bagian dalam, tentu saja bagian dalam akhirnya tidak akan dieksekusi.
Anton Arhipov
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.