Apa perbedaan antara cara penanganan berikut InterruptedException
? Apa cara terbaik untuk melakukannya?
try{
//...
} catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
ATAU
try{
//...
} catch(InterruptedException e) {
throw new RuntimeException(e);
}
EDIT: Saya juga ingin tahu skenario mana yang digunakan keduanya.
Jawaban:
Anda mungkin datang untuk menanyakan pertanyaan ini karena Anda telah memanggil metode yang melempar
InterruptedException
.Pertama-tama, Anda harus melihat
throws InterruptedException
apa itu: Bagian dari tanda tangan metode dan kemungkinan hasil dari memanggil metode yang Anda panggil. Jadi mulailah dengan merangkul fakta bahwa anInterruptedException
adalah hasil yang benar-benar valid dari pemanggilan metode.Sekarang, jika metode yang Anda panggil melempar pengecualian seperti itu, apa yang harus dilakukan metode Anda ? Anda dapat mengetahui jawabannya dengan memikirkan hal-hal berikut:
Apakah masuk akal untuk metode yang Anda laksanakan untuk melempar
InterruptedException
? Dengan kata lain, apakahInterruptedException
hasil yang masuk akal ketika memanggil metode Anda ?Jika ya , maka
throws InterruptedException
harus menjadi bagian dari tanda tangan metode Anda , dan Anda harus membiarkan pengecualian itu menyebar (yaitu, jangan menangkapnya sama sekali).Jika tidak , maka Anda tidak boleh mendeklarasikan metode Anda dengan
throws InterruptedException
dan Anda harus (harus!) Menangkap pengecualian. Sekarang dua hal penting untuk diingat dalam situasi ini:Seseorang mengganggu utas Anda. Seseorang mungkin ingin membatalkan operasi, menghentikan program dengan anggun, atau apa pun. Anda harus sopan kepada seseorang itu dan kembali dari metode Anda tanpa basa-basi lagi.
Meskipun metode Anda dapat menghasilkan nilai pengembalian yang masuk akal jika
InterruptedException
fakta bahwa utas telah terputus mungkin masih penting. Secara khusus, kode yang memanggil metode Anda mungkin tertarik pada apakah gangguan terjadi selama eksekusi metode Anda. Karena itu Anda harus mencatat fakta gangguan yang terjadi dengan mengatur bendera yang terputus:Thread.currentThread().interrupt()
Seharusnya sudah jelas bahwa melakukan itu
throw new RuntimeException(e)
adalah ide yang buruk. Tidak sopan kepada penelepon. Anda bisa membuat pengecualian runtime baru tetapi akar penyebab (seseorang ingin utas menghentikan eksekusi) mungkin hilang.Contoh lain:
Posting ini telah ditulis ulang sebagai artikel di sini .
sumber
interrupt()
untuk mempertahankan status yang terputus. Apa alasan di balik tidak melakukan ini padaThread.sleep()
?Thread.currentThread.interrupt()
dalamInterruptedException
blok catch akan hanya mengatur bendera interupsi. Itu tidak akan menyebabkan orang lainInterruptedException
terlempar / terperangkap diInterruptedException
blok tangkap luar .Kebetulan saya baru saja membaca tentang pagi ini dalam perjalanan untuk bekerja di Java Concurrency In Practice oleh Brian Goetz. Pada dasarnya dia mengatakan kamu harus melakukan satu dari tiga hal
Menyebarkan
InterruptedException
- Menyatakan metode Anda untuk membuang diperiksaInterruptedException
sehingga pemanggil Anda harus menghadapinya.Pulihkan interupsi - Terkadang Anda tidak dapat melempar
InterruptedException
. Dalam kasus ini Anda harus menangkapInterruptedException
dan mengembalikan status interupsi dengan memanggilinterrupt()
metode padacurrentThread
kode sehingga lebih tinggi tumpukan panggilan dapat melihat bahwa interupsi dikeluarkan, dan dengan cepat kembali dari metode. Catatan: ini hanya berlaku ketika metode Anda memiliki semantik "coba" atau "upaya terbaik", yaitu tidak ada hal penting yang akan terjadi jika metode tersebut tidak mencapai tujuannya. Misalnya,log()
atausendMetric()
mungkin metode seperti itu, atauboolean tryTransferMoney()
, tetapi tidakvoid transferMoney()
. Lihat di sini untuk detail lebih lanjut.Uninterruptibles
.Uninterruptibles
ambil alih kode boilerplate seperti pada contoh Tugas Noncancelable di JCIP § 7.1.3.sumber
Apa yang sedang Anda coba lakukan?
Itu
InterruptedException
dilemparkan ketika utas sedang menunggu atau tidur dan utas lain menyela itu menggunakaninterrupt
metode di kelasThread
. Jadi, jika Anda menangkap pengecualian ini, artinya utas telah terputus. Biasanya tidak ada gunanya meneleponThread.currentThread().interrupt();
lagi, kecuali jika Anda ingin memeriksa status "terputus" dari utas dari tempat lain.Mengenai pilihan Anda yang lain untuk melempar
RuntimeException
, sepertinya bukan hal yang bijak untuk dilakukan (siapa yang akan menangkap ini? Bagaimana akan ditangani?) Tetapi sulit untuk mengatakan lebih banyak tanpa informasi tambahan.sumber
Thread.currentThread().interrupt()
menetapkan bendera yang terputus (lagi), yang memang berguna jika kita ingin memastikan bahwa gangguan tersebut diperhatikan dan diproses pada tingkat yang lebih tinggi.Bagi saya hal utama tentang ini adalah: InterruptedException bukanlah sesuatu yang salah, itu adalah utas yang melakukan apa yang Anda perintahkan. Oleh karena itu, rethrowing yang dibungkus dengan RuntimeException tidak masuk akal.
Dalam banyak kasus masuk akal untuk memikirkan kembali pengecualian yang dibungkus dengan RuntimeException ketika Anda berkata, saya tidak tahu apa yang salah di sini dan saya tidak bisa melakukan apa pun untuk memperbaikinya, saya hanya ingin keluar dari aliran pemrosesan saat ini dan tekan handler pengecualian aplikasi-lebar apa pun yang saya miliki sehingga dapat mencatatnya. Bukan itu masalahnya dengan InterruptedException, itu hanya utas yang menanggapi telah interupsi () memanggilnya, itu melempar InterruptedException untuk membantu membatalkan pemrosesan utas secara tepat waktu.
Jadi sebarkan InterruptedException, atau makan dengan cerdas (artinya di tempat di mana ia akan mencapai apa yang seharusnya dilakukan) dan reset flag interrupt. Perhatikan bahwa flag interrupt akan dihapus ketika InterruptedException dilemparkan; asumsi yang dibuat oleh pengembang Jdk library adalah bahwa menangkap jumlah pengecualian untuk menanganinya, jadi secara default flag dihapus.
Jadi jelas cara pertama lebih baik, contoh yang diposting kedua dalam pertanyaan tidak berguna kecuali jika Anda tidak mengharapkan utas benar-benar terganggu, dan menyela itu berarti kesalahan.
Inilah jawaban yang saya tulis menggambarkan bagaimana interupsi bekerja, dengan sebuah contoh . Anda dapat melihat dalam kode contoh di mana ia menggunakan InterruptedException untuk menyelamatkan dari loop sementara dalam metode run Runnable.
sumber
Pilihan default yang benar adalah menambahkan InterruptedException ke daftar lemparan Anda. Interrupt menunjukkan bahwa utas lain ingin utas Anda berakhir. Alasan permintaan ini tidak dibuat jelas dan sepenuhnya kontekstual, jadi jika Anda tidak memiliki pengetahuan tambahan, Anda harus menganggap itu hanya shutdown yang ramah, dan apa pun yang menghindari shutdown adalah respons yang tidak ramah.
Java tidak akan secara acak melempar InterruptedException, semua saran tidak akan memengaruhi aplikasi Anda, tetapi saya telah mengalami kasus di mana pengembang yang mengikuti strategi "menelan" menjadi sangat tidak nyaman. Sebuah tim telah mengembangkan serangkaian besar tes dan menggunakan Thread. Tidur banyak. Sekarang kami mulai menjalankan tes di server CI kami, dan kadang-kadang karena cacat dalam kode akan terjebak dalam menunggu permanen. Untuk membuat situasi lebih buruk, ketika mencoba untuk membatalkan pekerjaan CI itu tidak pernah ditutup karena Thread.Interrupt yang dimaksudkan untuk membatalkan tes tidak membatalkan pekerjaan. Kami harus masuk ke kotak dan mematikan proses secara manual.
Singkatnya, jika Anda hanya membuang InterruptedException Anda cocok dengan maksud default bahwa utas Anda harus diakhiri. Jika Anda tidak dapat menambahkan InterruptedException ke daftar lemparan Anda, saya akan membungkusnya dalam RuntimeException.
Ada argumen yang sangat rasional untuk dibuat bahwa InterruptedException harus menjadi RuntimeException itu sendiri, karena itu akan mendorong penanganan "default" yang lebih baik. Ini bukan RuntimeException hanya karena desainer menempel pada aturan kategoris bahwa RuntimeException harus mewakili kesalahan dalam kode Anda. Karena InterruptedException tidak muncul langsung dari kesalahan dalam kode Anda, itu tidak. Tetapi kenyataannya adalah bahwa sering terjadi InterruptedException muncul karena ada kesalahan dalam kode Anda, (yaitu loop tak berujung, dead-lock), dan Interrupt adalah beberapa metode thread lain untuk menangani kesalahan itu.
Jika Anda tahu ada pembersihan rasional yang harus dilakukan, maka lakukanlah. Jika Anda mengetahui alasan yang lebih dalam untuk Interrupt, Anda dapat mengambil penanganan yang lebih komprehensif.
Jadi secara ringkas pilihan Anda untuk penanganan harus mengikuti daftar ini:
sumber
Saya hanya ingin menambahkan satu opsi terakhir ke apa yang kebanyakan orang dan artikel sebutkan. Seperti yang dinyatakan oleh mR_fr0g, penting untuk menangani interupsi dengan benar dengan:
Menyebarkan InterruptException
Pulihkan status interupsi di Thread
Atau tambahan:
Tidak ada yang salah dengan menangani interupsi dengan cara kustom tergantung pada keadaan Anda. Karena interupsi adalah permintaan untuk pengakhiran, sebagai lawan dari perintah yang kuat, sangat sah untuk menyelesaikan pekerjaan tambahan untuk memungkinkan aplikasi menangani permintaan dengan anggun. Misalnya, jika Thread sedang Tidur, menunggu IO atau respons perangkat keras, ketika menerima Interupsi, maka sah untuk menutup koneksi dengan anggun sebelum mengakhiri utas.
Saya sangat merekomendasikan memahami topik ini, tetapi artikel ini adalah sumber informasi yang bagus: http://www.ibm.com/developerworks/java/library/j-jtp05236/
sumber
Saya akan mengatakan dalam beberapa kasus tidak apa-apa untuk tidak melakukan apa-apa. Mungkin bukan sesuatu yang seharusnya Anda lakukan secara default, tetapi jika seandainya tidak ada cara untuk interupsi terjadi, saya tidak yakin apa yang harus dilakukan (mungkin kesalahan logging, tapi itu tidak mempengaruhi aliran program).
Satu kasus akan jika Anda memiliki antrian tugas (pemblokiran). Jika Anda memiliki Thread daemon yang menangani tugas-tugas ini dan Anda tidak menyela Thread itu sendiri (sepengetahuan saya, jvm tidak menginterupsi thread daemon pada shutdown jvm), saya tidak melihat cara untuk interupsi terjadi, dan oleh karena itu bisa saja diabaikan saja. (Saya tahu bahwa utas daemon dapat dibunuh oleh jvm kapan saja dan karenanya tidak cocok dalam beberapa kasus).
EDIT: Kasus lain mungkin blok yang dijaga, setidaknya berdasarkan pada tutorial Oracle di: http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
sumber