Siapa yang memanggil metode Java Thread interrupt () jika saya tidak?

87

Saya telah membaca dan membaca kembali Java Concurrency in Practice, saya telah membaca beberapa utas di sini tentang masalah ini, saya telah membaca artikel IBM Dealing with InterruptedException namun ada sesuatu yang tidak saya pahami yang menurut saya dapat dipatahkan menjadi dua pertanyaan:

  1. Jika saya sendiri tidak pernah menyela utas lain, apa yang dapat memicu InterruptedException ?

  2. Jika saya sendiri tidak pernah menyela utas lain menggunakan interrupt () (katakanlah karena saya menggunakan cara lain untuk membatalkan utas kerja saya, seperti pil racun dan while (! Cancel) style loop [seperti yang dijelaskan di JCIP]), apa yang dimaksud dengan InterruptedException ? Apa yang harus saya lakukan setelah menangkapnya? Matikan aplikasi saya?

SintaksT3rr0r
sumber

Jawaban:

51

Mekanisme interupsi Thread adalah cara yang disukai untuk mendapatkan thread (yang bekerja sama) untuk merespons permintaan untuk menghentikan apa yang dilakukannya. Setiap utas (termasuk utas itu sendiri menurut saya) dapat memanggil utas interrupt().

Dalam praktiknya, kasus penggunaan normal untuk interrupt()melibatkan beberapa jenis kerangka kerja atau manajer yang memberi tahu beberapa utas pekerja untuk menghentikan apa yang mereka lakukan. Jika thread pekerja adalah "interrupt aware", ia akan melihat bahwa ia telah diinterupsi melalui sebuah pengecualian, atau dengan secara berkala memeriksa flag interupsinya. Saat memperhatikan bahwa utas telah terputus, utas yang berperilaku baik akan meninggalkan apa yang dilakukannya dan berakhir dengan sendirinya.

Dengan asumsi kasus penggunaan di atas, kode Anda kemungkinan besar akan terganggu jika dijalankan dalam framework Java atau dari beberapa thread pekerja. Dan ketika terputus, kode Anda harus meninggalkan apa yang dilakukannya dan menyebabkan dirinya sendiri diakhiri dengan cara yang paling tepat. Bergantung pada bagaimana kode Anda dipanggil, ini mungkin dilakukan dengan mengembalikan atau dengan memberikan beberapa pengecualian yang sesuai. Tapi mungkin seharusnya tidak menelepon System.exit(). (Aplikasi Anda tidak selalu tahu mengapa itu diinterupsi, dan pasti tidak tahu apakah ada utas lain yang perlu diinterupsi oleh kerangka kerja.)

Di sisi lain, jika kode Anda tidak dirancang untuk berjalan di bawah kendali beberapa kerangka kerja, Anda dapat membantah bahwa InterruptedExceptionini adalah pengecualian yang tidak terduga; yaitu bug. Dalam hal ini, Anda harus memperlakukan pengecualian seperti halnya bug lainnya; misalnya membungkusnya dalam pengecualian yang tidak dicentang, dan menangkap serta mencatatnya pada titik yang sama saat Anda menangani pengecualian tidak dicentang yang tidak terduga lainnya. (Alternatifnya, aplikasi Anda dapat mengabaikan interupsi dan terus melakukan apa yang dilakukannya.)


1) Jika saya sendiri tidak pernah menyela utas lain, apa yang dapat memicu InterruptedException?

Salah satu contohnya adalah jika Runnableobjek Anda dieksekusi menggunakan ExecutorServicedan shutdownNow()dipanggil pada layanan. Dan dalam teori, kumpulan utas pihak ketiga atau kerangka kerja manajemen utas dapat melakukan hal seperti ini secara sah.

2) Jika saya sendiri tidak pernah menyela utas lain menggunakan interrupt () ... lalu apa InterruptedExceptionartinya? Apa yang harus saya lakukan setelah menangkapnya? Matikan aplikasi saya?

Anda perlu menganalisis basis kode untuk mencari tahu apa yang membuat interrupt()panggilan dan mengapa. Setelah Anda mengetahuinya, Anda dapat menentukan >> bagian << aplikasi yang perlu Anda lakukan.

Sampai Anda tahu mengapa InterruptedExceptiondibuang, saya sarankan untuk memperlakukannya sebagai kesalahan yang sulit; misalnya mencetak stacktrace ke file log dan menutup aplikasi. (Jelas, itu tidak selalu merupakan jawaban yang benar ... tetapi intinya adalah bahwa ini adalah "bug", dan perlu diperhatikan oleh pengembang / pengelola.)

3) Bagaimana cara mengetahui siapa / apa yang menelepon interrupt()?

Tidak ada jawaban yang bagus untuk ini. Yang terbaik yang bisa saya sarankan adalah mengatur breakpoint pada Thread.interrupt()dan melihat tumpukan panggilan.

Stephen C
sumber
12

Jika Anda memutuskan untuk mengintegrasikan kode Anda dengan pustaka lain, mereka dapat memanggil interrupt()kode Anda. misal jika Anda memutuskan di masa depan untuk mengeksekusi kode Anda dalam ExecutorService , maka itu mungkin memaksa shutdown melalui interrupt().

Singkatnya, saya akan mempertimbangkan tidak hanya di mana kode Anda berjalan sekarang , tetapi dalam konteks apa kode itu dapat berjalan di masa depan. misalnya apakah Anda akan menaruhnya di perpustakaan? Sebuah wadah? Bagaimana orang lain akan menggunakannya? Apakah Anda akan menggunakannya kembali?

Brian Agnew
sumber
Saya pikir hanya shutdownNow yang memanggil metode interrupt (). Apakah benar untuk shutdown juga?
Harinder
9

Seperti yang ditunjukkan orang lain, menyela utas (sebenarnya, menyela panggilan pemblokiran) biasanya digunakan untuk tujuan keluar dengan bersih atau membatalkan aktivitas yang sedang berlangsung.

Namun, Anda tidak boleh memperlakukan InterruptedExceptionsendirian sebagai "perintah keluar". Alih-alih, Anda harus memikirkan interupsi sebagai alat untuk mengontrol status thread yang sedang berjalan, sama seperti yang Object.notify()dilakukan. Dengan cara yang sama seperti Anda memeriksa keadaan saat ini setelah bangun dari panggilan ke Object.wait()(Anda tidak berasumsi bahwa bangun berarti kondisi tunggu Anda telah terpenuhi), setelah didorong dengan interupsi, Anda harus memeriksa mengapa Anda diinterupsi . Biasanya ada cara untuk melakukan ini. Misalnya java.util.concurrent.FutureTaskmemiliki isCancelled()metode.

Contoh kode:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}
Øyvind Bakksjø
sumber
3

Masalah dengan pertanyaan itu adalah "aku". "Saya" biasanya mengacu pada satu contoh kelas. Maksud saya dengan itu, bahwa bagian tertentu dari kode tingkat rendah (kelas) tidak boleh bergantung pada implementasi seluruh sistem. Karena itu Anda memang harus membuat beberapa keputusan "arsitektural" (seperti platform apa yang akan dijalankan).

Interupsi tak terduga yang mungkin datang dari JRE adalah tugas yang dibatalkan di java.util.concurrentdan mematikan applet.

Penanganan interupsi thread biasanya ditulis dengan tidak benar. Oleh karena itu, saya menyarankan keputusan arsitektural untuk menghindari menyebabkan interupsi jika memungkinkan. Namun, interupsi penanganan kode harus selalu ditulis dengan benar. Tidak dapat mengambil interupsi dari platform sekarang.

Tom Hawtin - tackline
sumber
Hai Tom, saya ingat nama Anda dari cljp;) Nah, tepatnya: Saya sendiri tidak pernah harus membuang interrupt () ... Kecuali saya menangkap sebuah InterruptedException dan perlu menegaskan kembali status terputus tetapi ini masih belum 100% jelas bagi saya. Saya baru di sini dan terkejut dengan jumlah upvote dan jawaban / komentar (baik yang benar maupun yang salah): jelas itu adalah subjek yang tidak sepele atau, setidaknya, biasanya tidak dijelaskan dengan baik. Berkat semua posting, saya mulai mendapatkan gambaran yang lebih jelas tentang apa yang terjadi :)
SyntaxT3rr0r
3

Anda bisa mempelajarinya dengan membuat kelas thread Anda sendiri (extending java.lang.Thread) dan interrupt()metode overriding , di mana Anda merekam stacktrace ke, katakanlah, kolom String, dan kemudian transfer ke super.interrupt ().

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}
Weekens
sumber
1

Seperti yang telah disebutkan, pustaka lain dapat mengganggu utas Anda. Meskipun pustaka tidak memiliki akses eksplisit ke utas dari kode Anda, mereka masih bisa mendapatkan daftar utas yang sedang berjalan dan menghentikannya dengan cara itu dengan metode berikut .

mangoDrunk
sumber
1

Saya rasa saya mengerti mengapa Anda agak bingung tentang interupsi. Mohon pertimbangkan jawaban saya sejalan:

Jika saya sendiri tidak pernah menyela utas lain, apa yang dapat memicu InterruptedException ?

Pertama, Anda dapat mengganggu utas lainnya; Saya tahu bahwa di JCiP disebutkan bahwa Anda tidak boleh menginterupsi thread yang bukan milik Anda; Namun, pernyataan ini harus dipahami dengan benar. Artinya adalah bahwa kode Anda yang mungkin berjalan di utas arbitrer apa pun seharusnya tidak menangani gangguan karena karena ini bukan pemilik utas, kode tersebut tidak memiliki petunjuk tentang kebijakan interupsi. Jadi, Anda dapat meminta interupsi pada utas lain, tetapi biarkan pemiliknya mengambil tindakan interupsi; itu memiliki kebijakan interupsi yang dikemas di dalamnya, bukan kode tugas Anda; setidaknya bersikaplah sopan untuk memasang bendera interupsi!

Ada banyak cara mengapa masih ada interupsi, mungkin timeout, interupsi JVM, dll.

Jika saya sendiri tidak pernah menyela utas lain menggunakan interrupt () (katakanlah karena saya menggunakan cara lain untuk membatalkan utas kerja saya, seperti pil racun dan while (! Dibatalkan) gaya loop [seperti yang dijelaskan di JCIP]), apa yang dimaksud dengan InterruptedException? Apa yang harus saya lakukan setelah menangkapnya? Matikan aplikasi saya?

Anda harus sangat berhati-hati di sini; jika Anda memiliki utas yang melemparkan InterruptedException (IE), maka Anda tahu apa yang harus dilakukan setelah menangkapnya, katakanlah Anda dapat mematikan aplikasi / layanan Anda atau Anda dapat mengganti utas yang dimatikan ini dengan yang baru! Namun, jika Anda tidak memiliki utas, maka setelah menangkap IE, lontarkan ulang lebih tinggi ke tumpukan panggilan atau setelah melakukan sesuatu (mungkin logging), atur ulang status terputus sehingga kode yang memiliki utas ini, saat kontrol mencapainya, dapat belajar bahwa utas terputus dan karenanya mengambil tindakan sebagaimana mestinya karena hanya ia yang mengetahui kebijakan interupsi.

Semoga ini bisa membantu.

nawazish-stackoverflow
sumber
0

Kata- InterruptedExceptionkata bahwa rutinitas mungkin terputus, tetapi tidak harus begitu.

Jika Anda tidak mengharapkan interupsi, maka Anda harus memperlakukannya sebagai pengecualian tak terduga lainnya. Jika berada di bagian kritis di mana pengecualian tak terduga dapat memiliki konsekuensi yang mengerikan, mungkin yang terbaik adalah mencoba dan membersihkan sumber daya dan mematikan dengan baik (karena mendapatkan sinyal interupsi bahwa aplikasi Anda yang direkayasa dengan baik yang tidak bergantung pada interupsi sedang digunakan dengan cara yang tidak dirancang, jadi pasti ada sesuatu yang salah). Atau, jika kode yang dipermasalahkan adalah sesuatu yang tidak kritis atau sepele, Anda mungkin ingin mengabaikan (atau mencatat) interupsi dan melanjutkan.

Abu
sumber