Mengapa memohon Thread.currentThread.interrupt () dalam blok tangkapan InterruptException?

155

Mengapa memanggil metode Thread.currentThread.interrupt()di blok tangkap?

Hesey
sumber

Jawaban:

160

Ini dilakukan untuk menjaga status .

Ketika Anda menangkap InterruptExceptiondan menelannya, pada dasarnya Anda mencegah metode / grup utas tingkat tinggi dari memperhatikan interupsi. Yang bisa menyebabkan masalah.

Dengan menelepon Thread.currentThread().interrupt(), Anda mengatur bendera interupsi utas, sehingga penangan interupsi tingkat yang lebih tinggi akan melihatnya dan dapat menanganinya dengan tepat.

Java Concurrency in Practice membahas ini secara lebih rinci di Bab 7.1.3: Menanggapi Gangguan . Aturannya adalah:

Hanya kode yang menerapkan kebijakan interupsi utas yang dapat menelan permintaan interupsi. Tugas dan kode pustaka untuk tujuan umum tidak boleh menelan permintaan interupsi.

Péter Török
sumber
15
Dalam dokumentasi itu dinyatakan bahwa "Dengan konvensi, metode apa pun yang keluar dengan melempar InterruptedException status interupsi yang jelas ketika melakukannya. Saya pikir ini membuat jawaban lebih jelas dalam hal mengapa Anda perlu mempertahankan status interupsi.
Stelios Adamantidis
Perlu juga dicatat bahwa interrupt()panggilan adalah satu-satunya cara untuk mengatur bendera yang terputus begitu Anda menerima pemberitahuan tentang keadaan ini melalui "mekanisme pengiriman" lainnya - InterruptedExceptiondan ingin atau tidak dapat melemparkan kembali.
sevo
67

Saya pikir contoh kode ini membuat semuanya lebih jelas. Kelas yang melakukan pekerjaan:

   public class InterruptedSleepingThread extends Thread {

        @Override
        public void run() {
            doAPseudoHeavyWeightJob();
        }

        private void doAPseudoHeavyWeightJob() {
            for (int i=0;i<Integer.MAX_VALUE;i++) {
                //You are kidding me
                System.out.println(i + " " + i*2);
                //Let me sleep <evil grin>
                if(Thread.currentThread().isInterrupted()) {
                    System.out.println("Thread interrupted\n Exiting...");
                    break;
                }else {
                    sleepBabySleep();
                }
            }
        }

        /**
         *
         */
        protected void sleepBabySleep() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                Thread.currentThread().interrupt();
            }
        }
    }

Kelas Utama:

   public class InterruptedSleepingThreadMain {

        /**
         * @param args
         * @throws InterruptedException
         */
        public static void main(String[] args) throws InterruptedException {
            InterruptedSleepingThread thread = new InterruptedSleepingThread();
            thread.start();
            //Giving 10 seconds to finish the job.
            Thread.sleep(10000);
            //Let me interrupt
            thread.interrupt();
        }

    }

Coba panggil interupsi tanpa mengembalikan status.

Ajay George
sumber
13
jadi kesimpulannya adalah ??
Scott 混合 理论
3
Terima kasih. Saya mengerti maksud Anda sekarang: repl.it/@djangofan/InterruptedThreadExample
djangofan
20

catatan:

http://download.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html

Bagaimana cara menghentikan utas yang menunggu dalam waktu lama (mis., Untuk input)?

Agar teknik ini berfungsi, sangat penting bahwa setiap metode yang menangkap pengecualian interupsi dan tidak siap untuk menanganinya segera memasukkan kembali pengecualian. Kami mengatakan memasukkan kembali daripada memikirkan kembali, karena tidak selalu mungkin untuk memikirkan kembali pengecualian. Jika metode yang menangkap InterruptedException tidak dinyatakan untuk melempar pengecualian (dicentang) ini, maka metode itu harus "menyela kembali dirinya sendiri" dengan mantra berikut:

Thread.currentThread().interrupt();

Ini memastikan bahwa Thread akan membangkitkan kembali InterruptedException secepatnya.

Bert F
sumber
2

Saya akan menganggapnya sebagai praktik yang buruk atau setidaknya sedikit berisiko. Biasanya metode tingkat yang lebih tinggi tidak melakukan operasi pemblokiran dan mereka tidak akan pernah melihat di InterruptedExceptionsana. Jika Anda menyembunyikannya di setiap tempat Anda melakukan operasi interupsi, Anda tidak akan pernah mendapatkannya.

Satu-satunya alasan untuk Thread.currentThread.interrupt()dan tidak meningkatkan pengecualian lain atau menandakan permintaan interupsi dengan cara lain (misalnya mengatur interruptedvariabel variabel lokal di loop utama utas) adalah situasi di mana Anda benar-benar tidak dapat melakukan apa pun dengan pengecualian, seperti di finallyblok.

Lihat jawaban Péter Török, jika Anda ingin lebih memahami implikasi Thread.currentThread.interrupt()panggilan tersebut.

Piotr Findeisen
sumber
0

Rujuk dari java doc

Jika utas ini diblokir dalam permohonan wait (), join (), sleep (long), maka status interruptnya akan dihapus dan ia akan menerima InterruptedException.

Jika utas ini diblokir dalam operasi I / O, status interupsi utas akan ditetapkan, dan utas akan menerima ClosedByInterruptException.

Jika utas ini diblokir dalam Pemilih maka status interupsi utas akan ditetapkan dan akan segera kembali dari operasi pemilihan.

Jika tidak ada kondisi sebelumnya yang bertahan maka status interupsi utas ini akan ditetapkan.

Jadi, jika Anda mengubah metode sleepBabySleep () di @Ajay George Answer untuk operasi I / O atau hanya sysout, Anda tidak perlu mengatur status kembali untuk menghentikan program. (BTW, mereka bahkan tidak membuang InterruptedException)

Sama seperti @ Péter Török berkata => Ini dilakukan untuk menjaga status. (Dan khusus untuk metode yang akan membuang InterruptedException)

Michael Ouyang
sumber