Kata pengantar
Untuk interruptedException, cara yang umum untuk menanganinya adalah dengan "menelan" itu - menangkapnya dan tidak melakukan apa -apa (atau merekamnya, tapi itu tidak jauh lebih baik) - seperti daftar 4 nanti. Sayangnya, pendekatan ini mengabaikan fakta bahwa interupsi dapat terjadi selama periode ini, dan interupsi dapat menyebabkan aplikasi kehilangan kemampuan untuk membatalkan aktivitas atau menutupnya dalam waktu.
Metode pemblokiran
Ketika suatu metode melempar ExcepedException, itu tidak hanya memberi tahu Anda bahwa itu dapat melemparkan pengecualian cek tertentu, tetapi juga memberi tahu Anda sesuatu yang lain. Misalnya, ini memberi tahu Anda bahwa itu adalah metode pemblokiran, yang akan mencoba menghilangkan pemblokiran dan kembali sedini mungkin jika Anda merespons dengan benar.
Metode pemblokiran berbeda dari metode umum yang membutuhkan waktu lama untuk dijalankan. Penyelesaian metode umum hanya tergantung pada apa yang dilakukannya dan apakah ada sumber daya komputasi yang cukup tersedia (siklus dan memori CPU). Penyelesaian metode pemblokiran juga tergantung pada beberapa peristiwa eksternal, seperti kedaluwarsa timer, penyelesaian I/O, atau tindakan utas lain (lepaskan kunci, atur bendera, atau tempatkan tugas dalam antrian kerja). Metode umum berakhir setelah pekerjaan mereka dilakukan, sementara metode pemblokiran lebih sulit untuk diprediksi karena mereka bergantung pada peristiwa eksternal. Metode pemblokiran dapat memengaruhi respons karena sulit untuk diprediksi kapan mereka akan berakhir.
Metode pemblokiran mungkin tidak diakhiri karena tidak dapat menunggu acara yang ditunggu-tunggu, jadi sangat berguna untuk membuat metode pemblokiran dapat dibatalkan (dan seringkali sangat berguna jika metode non-blocking jangka panjang dapat dibatalkan). Operasi yang dapat dibatalkan mengacu pada operasi yang dapat diakhiri dari luar sebelum selesai normal. Mekanisme interupsi yang disediakan oleh Thread dan didukung oleh thread.sleep () dan Object.Wait () adalah mekanisme pembatalan; Ini memungkinkan satu utas untuk meminta utas lain untuk menghentikan apa yang dilakukannya. Ketika suatu metode melempar ExcepedException, ia memberi tahu Anda bahwa jika utas yang mengeksekusi metode tersebut terganggu, ia akan mencoba menghentikan apa yang dilakukan dan kembali sebelumnya, dan dengan melempar Exception interrupted, ia kembali terlebih dahulu. Metode perpustakaan pemblokiran yang berperilaku baik harus merespons interupsi dan melemparkan Exception interrupted sehingga dapat digunakan dalam kegiatan yang dapat dibatalkan tanpa mempengaruhi respons.
Interupsi utas
Setiap utas memiliki atribut boolean yang terkait dengannya, yang mewakili status terputus utas. Keadaan interupsi salah pada awalnya; Ketika utas lain mengganggu utas dengan memanggil utas. Jika utas itu menjalankan metode pemblokiran interruptible tingkat rendah, seperti thread.sleep (), thread.join (), atau object.wait (), itu akan membuka blokir dan melempar Exception interrupted. Kalau tidak, interrupt () cukup mengatur status interupsi utas. Setelah kode yang berjalan di utas yang terganggu dapat melakukan polling keadaan interupsi untuk melihat apakah diminta untuk menghentikan apa yang dilakukannya. Status interupsi dapat dibaca oleh utas.
Gangguan adalah mekanisme kolaboratif. Ketika satu utas mengganggu utas lain, utas yang terganggu tidak selalu menghentikan apa yang dilakukannya segera. Sebaliknya, interupsi adalah permintaan yang sopan ke utas lain untuk menghentikan apa yang dilakukannya ketika bersedia dan nyaman. Beberapa metode, seperti thread.sleep (), menerima permintaan seperti itu dengan sangat serius, tetapi setiap metode tidak selalu menanggapi interupsi. Untuk permintaan interupsi, metode yang tidak diblokir tetapi masih membutuhkan waktu lama untuk dieksekusi dapat polling status interupsi dan kembali terlebih dahulu saat terganggu. Anda dapat mengabaikan permintaan interupsi sesuka hati, tetapi melakukan hal itu akan memengaruhi respons.
Salah satu manfaat dari sifat kolaboratif dari gangguan adalah memberikan fleksibilitas yang lebih besar untuk membangun kegiatan yang dapat dibatalkan dengan aman. Kami jarang ingin suatu kegiatan segera berhenti; Jika aktivitas dibatalkan saat pembaruan sedang berlangsung, struktur data program mungkin tidak konsisten. Interupsi memungkinkan aktivitas yang dapat dibatalkan untuk membersihkan pekerjaan yang berkelanjutan, memulihkan invarian, memberi tahu kegiatan lain yang akan dibatalkan sebelum diakhiri.
Tangani interruptedException
Jika melempar Exception Interruptedsception berarti bahwa metode adalah metode pemblokiran, memanggil metode pemblokiran berarti bahwa metode Anda juga merupakan metode pemblokiran, dan Anda harus memiliki semacam strategi untuk menangani Exterrupted Exception. Strategi termudah biasanya untuk melempar diri sendiri yang terputus, seperti yang ditunjukkan dalam kode dalam metode puttask () dan gettask () dalam daftar 1. Melakukan hal itu membuat metode ini merespons interupsi dan cukup menambahkan ExcepedException ke klausa lemparan.
Listing 1. Tidak menangkap interruptException, menyebarkannya ke penelepon
kelas publik TaskQueue {private static final int max_tasks = 1000; Private BlockingQueue <Keck> antrian = baru LinkedBlockingQueue <Keck> (MAX_TASKS); public void puttask (tugas r) melempar interruptedException {queue.put (r); } tugas publik getTask () melempar InterruptedException {return queue.take (); }} Terkadang beberapa pekerjaan pembersihan diperlukan sebelum pengecualian disebarkan. Dalam hal ini, Anda dapat menangkap Excepion Exception, melakukan pembersihan, dan kemudian melempar pengecualian. Listing 2 menunjukkan teknik ini, mekanisme yang digunakan untuk mencocokkan pemain dalam layanan game online. Metode MatchPlayers () menunggu dua pemain tiba dan kemudian memulai permainan baru. Jika metode ini terganggu ketika satu pemain telah tiba tetapi pemain lain belum tiba, itu akan mengembalikan pemain itu dalam antrian dan melemparkan kembali interruptedException sehingga permintaan pemain ke permainan tidak akan hilang.
Listing 2. Lakukan pekerjaan pembersihan khusus tugas sebelum melempar ulang ExterruptException
PlayerMatcher kelas publik {Pemain Pribadi Sourcource; PlayerMatcher publik (pemain sumber daya) {this.players = pemain; } public void matchplayers () melempar InterruptedException {coba {player playerOne, playertwo; while (true) {playerOne = playertwo = null; // tunggu dua pemain tiba dan memulai permainan permainan baru = pemain.WaitForPlayer (); // bisa melempar IE playertwo = playes.waitforplayer (); // bisa melempar IE startNewGame (playerOne, playertwo); }} catch (InterruptedException e) {// Jika kami punya satu pemain dan terganggu, mengembalikan pemain itu jika (playerOne! = null) player.addfirst (playerOne); // kemudian menyebarkan lemparan pengecualian E; }}} Jangan berhenti menelan hidup -hidup
Terkadang melempar Exception interrupted tidak tepat, misalnya, ketika tugas yang ditentukan oleh runnable memanggil metode interruptible. Dalam hal ini, ExterruptedException tidak dapat dilemparkan kembali, tetapi Anda juga tidak ingin melakukan apa pun. Ketika metode pemblokiran mendeteksi interupsi dan melempar Exception interrupted, itu membersihkan keadaan interupsi. Jika EXTERRUCTEDEXCEPTION ditangkap tetapi tidak dapat dilemparkan kembali, maka bukti interupsi terjadi harus disimpan sehingga kode tingkat yang lebih tinggi dalam tumpukan panggilan dapat mengetahui interupsi dan menanggapi itu. Tugas ini dapat dilakukan dengan memanggil interrupt () untuk "mengulangi" utas saat ini, seperti yang ditunjukkan dalam Listing 3. Setidaknya, setiap kali Exception Exception ditangkap dan tidak dilemparkan ulang, utas saat ini dipindahkan kembali sebelum kembali.
Listing 3. Melanjutkan keadaan terputus setelah menangkap interrupted exception
TaskRunner kelas publik mengimplementasikan runnable {private blockingqueue <Keck> antrian; Public TaskRunner (BlockingQueue <Keck> antrian) {this.queue = antrian; } public void run () {coba {while (true) {Task Task = queue.take (10, timeunit.seconds); Task.execute (); }} catch (InterruptedException e) {// Kembalikan status interrupted thread.currentThread (). Interrupt (); }}} Hal terburuk yang harus dilakukan ketika berhadapan dengan interruptedException adalah menelannya mentah-menangkapnya, dan kemudian tidak melemparkannya kembali atau memperkuat kembali keadaan interupsi utas. Untuk pengecualian yang Anda tidak tahu bagaimana menghadapinya, cara paling standar untuk menangani adalah dengan menangkapnya dan merekamnya, tetapi metode ini masih seperti interupsi mentah, karena kode tingkat yang lebih tinggi dalam tumpukan panggilan masih tidak dapat memperoleh informasi tentang pengecualian. (Tidak bijaksana untuk hanya merekam interrupted exception, karena sudah terlambat untuk memprosesnya ketika seseorang datang untuk membaca log.) Listing 4 menunjukkan pola yang banyak digunakan, yang juga merupakan pola gangguan menelan mentah:
Daftar 4. Gangguan menelan mentah - jangan lakukan ini
// Jangan lakukan TaskRunner kelas publik ini mengimplementasikan runnable {private blockingqueue <Keck> antrian; Public TaskRunner (BlockingQueue <Keck> antrian) {this.queue = antrian; } public void run () {coba {while (true) {Task Task = queue.take (10, timeunit.seconds); Task.execute (); }} catch (interruptedException ditelan) { / * Jangan lakukan ini - kembalikan status yang terganggu sebagai gantinya * /}}} Jika ExterruptedException tidak dapat dilemparkan kembali, terlepas dari apakah Anda berencana untuk memproses permintaan interupsi atau tidak, Anda masih perlu menghubungkan kembali utas saat ini, karena satu permintaan interupsi mungkin memiliki beberapa "penerima". Implementasi Thread Thread Pool (ThreadPoolExecutor) Standar bertanggung jawab atas gangguan, sehingga mengganggu tugas dalam kumpulan utas yang berjalan dapat memiliki efek ganda. Salah satunya adalah membatalkan tugas, dan yang lainnya adalah memberi tahu utas eksekusi bahwa kumpulan utas akan ditutup. Jika tugas melahap permintaan, utas pekerja tidak akan tahu bahwa ada interupsi yang diminta, menunda penutupan aplikasi atau layanan.
Menerapkan tugas yang dibatalkan
Tidak ada semantik khusus untuk interupsi dalam spesifikasi bahasa, tetapi dalam program yang lebih besar, sulit untuk mempertahankan semantik interupsi kecuali pembatalan. Bergantung pada aktivitas apa itu, pengguna dapat meminta pembatalan melalui GUI atau melalui mekanisme jaringan, seperti JMX atau layanan web. Logika program juga dapat diminta untuk membatalkan. Misalnya, perayap web akan secara otomatis menutup sendiri jika mendeteksi bahwa disk penuh, jika tidak, algoritma paralel akan memulai beberapa utas untuk mencari berbagai area ruang solusi, dan membatalkan utas tersebut setelah salah satu utas menemukan solusi.
Hanya karena tugas yang dapat dibatalkan tidak berarti bahwa permintaan interupsi perlu segera ditanggapi. Untuk tugas yang menjalankan kode dalam satu loop, biasanya hanya perlu untuk memeriksa interupsi sekali untuk setiap iterasi loop. Bergantung pada berapa lama loop dieksekusi, mungkin perlu beberapa waktu untuk kode apa pun untuk memperhatikan bahwa utas telah terganggu (baik polling status interupsi dengan memanggil utas. Jika tugas harus responsif, ia dapat lebih sering melakukan polling keadaan interupsi. Metode pemblokiran biasanya membentangkan keadaan interupsi segera di inlet dan, jika diatur untuk meningkatkan responsif, ia juga melempar Exception interrupted.
Satu -satunya waktu Anda bisa berhenti menelan hidup -hidup adalah bahwa Anda tahu utasnya akan keluar. Skenario ini hanya terjadi ketika kelas yang memanggil metode interruptible adalah bagian dari utas, bukan kode perpustakaan umum atau umum, seperti yang ditunjukkan dalam Listing 5. Listing 5 membuat utas yang mencantumkan bilangan prima sampai terganggu, yang juga diizinkan untuk keluar ketika terganggu. Loop yang digunakan untuk mencari bilangan prima memeriksa gangguan di dua tempat: satu adalah untuk polling metode yang terputus () di kepala loop while, dan yang lainnya adalah memanggil metode blocking blockingqueue.put ().
Daftar 5. Jika Anda tahu bahwa utasnya akan keluar, Anda dapat menelan interupsi
PrimeProducer kelas publik memperluas thread {private final blockingqueue <Biginteger> antrian; PrimeProducer (blockingqueue <Biginteger> antrian) {this.queue = antrian; } public void run () {coba {biginteger p = biginteger.one; while (! thread.currentThread (). isInterrupted ()) queue.put (p = p.nextprobablePrime ()); } catch (interruptedException dikonsumsi) { / * Izinkan utas keluar * /}} public void cancel () {interrupt (); }} Metode pemblokiran yang tidak bisa dipatahkan
Tidak semua metode pemblokiran melempar ExterruptedException. Blok kelas input dan output. Namun, untuk soket I/O, jika sebuah utas menutup soket, operasi pemblokiran I/O pada soket itu akan berakhir lebih awal dan socketException dilemparkan. Kelas I/O yang tidak memblokir di java.nio tidak mendukung I/O yang dapat diganggu, tetapi mereka juga dapat diblokir dengan menutup saluran atau meminta bangun pada pemilih. Demikian pula, mencoba untuk memperoleh kunci internal (memasuki blok yang disinkronkan) tidak dapat terganggu, tetapi Reentrantlock mendukung mode akuisisi yang interupsi.
Tugas yang tidak dibuang
Beberapa tugas menolak untuk terputus, yang membuat mereka tidak beralkohol. Namun, bahkan tugas yang tidak dapat dibatalkan harus mencoba untuk melestarikan keadaan interupsi jika kode tingkat yang lebih tinggi pada tumpukan panggilan perlu memproses interupsi setelah tugas yang tidak dapat dibatalkan selesai. Listing 6 menunjukkan metode yang menunggu antrian pemblokiran sampai item yang tersedia muncul dalam antrian, terlepas dari apakah itu terganggu atau tidak. Untuk kenyamanan, ia melanjutkan keadaan interupsi setelah akhir di blok akhirnya, agar tidak menghilangkan penelepon dari permintaan interupsi. ;
Listing 6. Tugas yang tak ada artinya yang mengembalikan keadaan terputus sebelum kembali
Tugas Publik GetNextTask (BlockingQueue <Keck> antrian) {boolean interrupted = false; coba {while (true) {coba {return queue.take (); } catch (InterruptedException e) {interrupted = true; // jatuh dan coba lagi}}} akhirnya {if (interrupted) thread.currentThread (). interrupt (); }} Meringkaskan
Anda dapat menggunakan mekanisme interupsi kolaborasi yang disediakan oleh Platform Java untuk membangun strategi pembatalan yang fleksibel. Kegiatan dapat memutuskan dengan kebijaksanaan mereka sendiri apakah mereka dapat dibatalkan atau tidak dapat dibatalkan, dan bagaimana merespons interupsi, dan juga dapat menunda interupsi jika pengembalian segera akan membahayakan integritas aplikasi. Bahkan jika Anda ingin mengabaikan interupsi sepenuhnya dalam kode Anda, Anda harus memastikan bahwa keadaan interupsi dipulihkan tanpa melemparkannya kembali, sehingga kode yang menyebutnya tidak tahu apa interupsi yang terjadi. Di atas adalah konten lengkap dari teori Java dan praktik menangani pengecualian Exception. Saya harap artikel ini akan membantu Anda. Jika Anda memiliki pertanyaan, silakan tinggalkan pesan untuk diskusi.