Pada artikel sebelumnya, saya memperkenalkan metode menggunakan Java8 untuk mengimplementasikan pola pengamat (Bagian 1). Artikel ini terus memperkenalkan pengetahuan yang relevan dari pola pengamat Java8. Konten spesifiknya adalah sebagai berikut:
Implementasi yang aman-utas
Bab sebelumnya memperkenalkan implementasi pola pengamat di lingkungan Java modern. Meskipun sederhana tetapi lengkap, implementasi ini mengabaikan masalah utama: keamanan utas. Sebagian besar aplikasi Java yang terbuka adalah multi-threaded, dan mode pengamat sebagian besar digunakan dalam sistem multi-threaded atau asinkron. Misalnya, jika layanan eksternal memperbarui basis data, aplikasi juga akan menerima pesan secara tidak sinkron dan kemudian memberi tahu komponen internal untuk memperbarui dalam mode pengamat, alih -alih mendaftarkan dan mendengarkan layanan eksternal secara langsung.
Keamanan utas dalam mode pengamat terutama difokuskan pada tubuh mode, karena konflik utas cenderung terjadi ketika memodifikasi koleksi pendengar terdaftar. Misalnya, satu utas mencoba menambahkan pendengar baru, sementara utas lainnya mencoba menambahkan objek hewan baru, yang memicu pemberitahuan untuk semua pendengar terdaftar. Mengingat urutan urutan, utas pertama mungkin atau mungkin belum menyelesaikan pendaftaran pendengar baru sebelum pendengar terdaftar menerima pemberitahuan tentang hewan yang ditambahkan. Ini adalah kasus klasik kompetisi sumber daya utas, dan fenomena inilah yang memberi tahu pengembang bahwa mereka membutuhkan mekanisme untuk memastikan keamanan utas.
Solusi termudah untuk masalah ini adalah: semua operasi yang mengakses atau memodifikasi daftar pendengar pendaftaran harus mengikuti mekanisme sinkronisasi Java, seperti:
Publik yang disinkronkan animalAddedListener Registeranimaladdedlistener (animaladdedlistener listener) {/*...*/} public disinkronkan void unregisteranimaladdedlistener (animalAddedListener pendengar) {/*...* (hewani (hewani) {hius {hewine {hewine {{hius {{hius {{hius {{hius {{public noifyAmalAddededlendedlendedlendedlendedlendedlendedlended (/*Dengan cara ini, pada saat yang sama, hanya satu utas yang dapat memodifikasi atau mengakses daftar pendengar terdaftar, yang dapat berhasil menghindari masalah kompetisi sumber daya, tetapi masalah baru muncul, dan kendala seperti itu terlalu ketat (untuk informasi lebih lanjut tentang kata kunci yang disinkronkan dan model konkurensi Java, silakan merujuk ke halaman web resmi). Melalui sinkronisasi metode, akses bersamaan ke daftar pendengar dapat diamati setiap saat. Mendaftarkan dan mencabut pendengar adalah operasi penulisan untuk daftar pendengar, sambil memberi tahu pendengar untuk mengakses daftar pendengar adalah operasi read-only. Karena akses melalui pemberitahuan adalah operasi baca, beberapa operasi pemberitahuan dapat dilakukan secara bersamaan.
Oleh karena itu, selama tidak ada pendaftaran atau pencabutan pendengar, selama pendaftaran tidak terdaftar, selama sejumlah pemberitahuan bersamaan dapat dieksekusi secara bersamaan tanpa memicu persaingan sumber daya untuk daftar pendengar terdaftar. Tentu saja, kompetisi sumber daya dalam situasi lain telah ada sejak lama. Untuk mengatasi masalah ini, penguncian sumber daya untuk ReadWritelock dirancang untuk mengelola operasi baca dan menulis secara terpisah. Kode implementasi ThreadSafezoo yang aman dari kelas Zoo adalah sebagai berikut:
Public Class ThreadSafezoo {private final readwritelock readwritelock = baru reentrantreadwritelock (); Readlock kunci akhir yang dilindungi = readwritelock.readlock (); Writelock kunci akhir yang dilindungi = readwritelock.writelock (); Daftar pribadi <acalan> hewan = new arraylist <> (); daftar pribadi <animaladdedlistener> pendengar = Daftar Array baru <> (); public void addanimal (hewan hewan) {// Tambahkan hewan ke daftar hewan binatangthis. listenersthis.notifyAnimaladdedlisteners (hewan);} public animalAddedDistenener registeranimaladdedlistener (animalAddedDistener listener) {// Kunci daftar pendengar untuk menulis this.writelock.lock (); coba {// tambahkan pendengar ke daftar pendengar yang terdaftar. lockthis.writelock.unlock ();} return listener;} public void unregisteranimaladdedlistener (animalAddedistener listener) {// Kunci daftar pendengar untuk menulis ini.writelock.lock (); coba {// hapus pendengar dari daftar pendengar yang terdaftar. lockthis.writelock.unlock ();}} public void notifyanimaladdedlisteners (hewan hewan) {// Kunci daftar pendengar untuk membaca ini {// Buka kunci pembaca lockthis.readlock.unlock ();}}}Melalui penyebaran tersebut, implementasi subjek dapat memastikan keamanan utas dan banyak utas dapat mengeluarkan pemberitahuan secara bersamaan. Namun terlepas dari ini, masih ada dua masalah kompetisi sumber daya yang tidak dapat diabaikan:
Akses bersamaan ke setiap pendengar. Beberapa utas dapat memberi tahu pendengar bahwa hewan baru diperlukan, yang berarti bahwa pendengar dapat dipanggil oleh banyak utas secara bersamaan.
Akses Bersamaan ke Daftar Hewan. Beberapa utas dapat menambahkan objek ke daftar hewan secara bersamaan. Jika urutan pemberitahuan memiliki dampak, itu dapat menyebabkan persaingan sumber daya, yang membutuhkan mekanisme pemrosesan operasi bersamaan untuk menghindari masalah ini. Jika daftar pendengar terdaftar menerima pemberitahuan untuk menambahkan Animal2 dan kemudian menerima pemberitahuan untuk menambahkan hewan, kompetisi sumber daya akan terjadi. Namun, jika penambahan Animal1 dan Animal2 dilakukan oleh utas yang berbeda, juga dimungkinkan untuk menyelesaikan penambahan hewan 1 sebelum hewan. Secara khusus, Thread 1 menambahkan Animal1 sebelum memberi tahu pendengar dan mengunci modul, Thread 2 menambahkan Animal2 dan memberi tahu pendengar, dan kemudian Thread 1 memberi tahu pendengar bahwa Animal1 telah ditambahkan. Meskipun persaingan sumber daya dapat diabaikan ketika urutan urutan tidak dipertimbangkan, masalahnya nyata.
Akses Bersamaan dengan Pendengar
Pendengar akses bersamaan dapat diimplementasikan dengan memastikan keamanan utas pendengar. Mematuhi semangat "tanggung jawab diri" kelas, pendengar memiliki "kewajiban" untuk memastikan keamanan utasnya sendiri. Misalnya, untuk pendengar yang dihitung di atas, meningkatkan atau mengurangi jumlah hewan dengan banyak utas dapat menyebabkan masalah keamanan utas. Untuk menghindari masalah ini, perhitungan jumlah hewan harus berupa operasi atom (variabel atom atau sinkronisasi metode). Kode solusi spesifik adalah sebagai berikut:
Thread kelas publikfecounttingAnimaladdedlistener mengimplementasikan animalAddedListener {private static atomiclong animalsaddedcount = new atomiclong (0);@overridepublic void updateanimaladded (hewan total) {// bertambah jumlah hewan yang disadarkan.Kode solusi sinkronisasi metode adalah sebagai berikut:
Kelas Publik Countanimaladdedlistener mengimplementasikan animalAddedListener {private static int animalsaddedcount = 0; @Overridepublic disinkronkan void updateanimaladded (hewan hewan) {// bertambah jumlah hewanSystem.out.println ("Total hewan ditambahkan:" +eddeddeddedcount);Harus ditekankan bahwa pendengar harus memastikan keamanan utasnya sendiri. Subjek perlu memahami logika internal pendengar, daripada hanya memastikan keamanan utas untuk mengakses dan memodifikasi pendengar. Jika tidak, jika beberapa subjek berbagi pendengar yang sama, setiap kelas subjek harus menulis ulang kode yang aman. Jelas, kode seperti itu tidak cukup ringkas, jadi utas-aman perlu diimplementasikan di kelas pendengar.
Pemberitahuan pendengar yang dipesan
Ketika pendengar diharuskan untuk dieksekusi secara tertib, kunci baca dan tulis tidak dapat memenuhi kebutuhan, dan mekanisme baru perlu diperkenalkan untuk memastikan bahwa urutan panggilan fungsi notify konsisten dengan urutan di mana hewan ditambahkan ke kebun binatang. Beberapa orang telah mencoba mengimplementasikannya menggunakan sinkronisasi metode, tetapi menurut pengenalan sinkronisasi metode dalam dokumentasi Oracle, dapat dilihat bahwa sinkronisasi metode tidak memberikan manajemen pesanan eksekusi operasi. Ini hanya memastikan bahwa operasi atom tidak terganggu, dan tidak menjamin urutan utas eksekusi pertama datang-pertama (FIFO). ReentrantReadWritelock dapat mengimplementasikan perintah eksekusi seperti itu, kodenya adalah sebagai berikut:
Public Class ordhreadSafezoo {private final readwritelock readwritelock = baru reentrantreadwritelock (true); Readlock kunci akhir yang dilindungi = readwritelock.readlock (); Writelock kunci akhir yang dilindungi = readwritelock.writelock (); Daftar pribadi <acalan> hewan = new arraylist <> (); daftar pribadi <animaladdedlistener> pendengar = Daftar Array baru <> (); public void addanimal (hewan hewan) {// Tambahkan hewan ke daftar hewan binatangthis. listenersthis.notifyAnimaladdedlisteners (hewan);} public animalAddedDistenener registeranimaladdedlistener (animalAddedDistener listener) {// Kunci daftar pendengar untuk menulis this.writelock.lock (); coba {// tambahkan pendengar ke daftar pendengar yang terdaftar. lockthis.writelock.unlock ();} return listener;} public void unregisteranimaladdedlistener (animalAddedistener listener) {// Kunci daftar pendengar untuk menulis ini.writelock.lock (); coba {// hapus pendengar dari daftar pendengar yang terdaftar. lockthis.writelock.unlock ();}} public void notifyanimaladdedlisteners (hewan hewan) {// Kunci daftar pendengar untuk membaca ini {// Buka kunci pembaca lockthis.readlock.unlock ();}}}Dengan cara ini, daftar, lepaskan dan beri tahu fungsi akan mendapatkan izin kunci baca dan tulis dalam urutan pertama-dalam-pertama (FIFO). Misalnya, Thread 1 mendaftar pendengar, Thread 2 mencoba memberi tahu pendengar terdaftar setelah memulai operasi pendaftaran, Thread 3 mencoba memberi tahu pendengar yang terdaftar ketika Thread 2 sedang menunggu kunci baca-saja, mengadopsi metode pemesanan adil, utas 1 melengkapi operasi pendaftaran terlebih dahulu, kemudian Thread 2 dapat memberi tahu pendengar, dan akhirnya utas pemberitahuan pendengar. Ini memastikan bahwa urutan eksekusi dan urutan awal tindakan konsisten.
Jika sinkronisasi metode diadopsi, meskipun Thread 2 mengantri terlebih dahulu untuk menempati sumber daya, Thread 3 masih dapat memperoleh kunci sumber daya sebelum utas 2, dan tidak dapat dijamin bahwa Thread 2 memberi tahu pendengar terlebih dahulu daripada utas 3. Kunci untuk masalah ini adalah: metode pemesanan adil dapat memastikan bahwa utas dieksekusi dalam urutan di mana sumber daya diterapkan. Mekanisme pesanan kunci baca dan tulis sangat rumit. Anda harus merujuk pada dokumentasi resmi ReentrantReadWritelock untuk memastikan bahwa logika kunci cukup untuk menyelesaikan masalah.
Keamanan utas telah diimplementasikan sejauh ini, dan kelebihan dan kerugian dari mengekstraksi logika topik dan merangkum kelas mixin -nya menjadi unit kode yang berulang akan diperkenalkan dalam bab -bab berikut.
Logika tema dienkapsulasi ke kelas mixin
Sangat menarik untuk merangkum implementasi desain pola pengamat yang disebutkan di atas ke dalam kelas mixin target. Secara umum, pengamat dalam mode pengamat berisi koleksi pendengar terdaftar; daftar fungsi yang bertanggung jawab untuk mendaftarkan pendengar baru; Fungsi yang tidak terdaftar yang bertanggung jawab untuk mencabut fungsi yang tidak terdaftar dan memberi tahu fungsi yang bertanggung jawab untuk memberi tahu pendengar. Untuk contoh di atas kebun binatang, semua operasi lain dari kelas kebun binatang kecuali bahwa daftar hewan diperlukan untuk masalah ini adalah untuk mengimplementasikan logika subjek.
Kasus kelas mixin ditunjukkan di bawah ini. Perlu dicatat bahwa untuk membuat kode lebih ringkas, kode tentang keamanan utas dihapus di sini:
Kelas abstrak publik ObservableSubjectMixin <D listenerType> {Daftar pribadi <DistenerType> listeners = new ArrayList <> (); Public listenerType registerListener (listenerType listener) {// tambahkan pendengar ke daftar listener {listener {listener (pendengar) yang terdaftar {listener (listener); listener return;} public listenersthis.listeners.add (listener); return listener;} public listenersthis.listeners.add (listener); return listener;} public void void publican Dari daftar pendengar terdaftar ini.listeners.remove (pendengar);} public void notifylisteners (konsumen <? Super listenerType> algoritma) {// Jalankan beberapa fungsi pada masing -masing pendengar.listeners.foreach (algoritm);}}}Karena informasi antarmuka dari tipe pendengar terdaftar tidak disediakan, pendengar tertentu tidak dapat diberitahu secara langsung, sehingga perlu untuk memastikan universalitas fungsi pemberitahuan dan memungkinkan klien untuk menambahkan beberapa fungsi, seperti menerima pencocokan parameter jenis parameter generik yang berlaku untuk masing -masing pendengar. Kode implementasi spesifik adalah sebagai berikut:
ZoousingMixin kelas publik memperluas ObservableSubjectMixin <animaladdedlistener> {Daftar pribadi <nejala> hewan = new arraylist <> (); public void addanimal (hewan hewan) {// Tambahkan hewan ke daftar hewan yang terdaftar. listener.updateanimaladded (hewan));}}Keuntungan terbesar dari teknologi kelas mixin adalah merangkum subjek berpola pengamat ke dalam kelas yang dapat diulang, daripada mengulangi logika di setiap kelas subjek. Selain itu, metode ini membuat implementasi kelas kebun binatang lebih sederhana, hanya menyimpan informasi hewan tanpa mempertimbangkan cara menyimpan dan memberi tahu pendengar.
Namun, menggunakan kelas mixin bukan hanya keuntungan. Misalnya, bagaimana jika Anda ingin menyimpan beberapa jenis pendengar? Misalnya, juga perlu untuk menyimpan pendengar yang dicerna. Kelas Mixin adalah kelas abstrak. Beberapa kelas abstrak tidak dapat diwariskan pada saat yang sama di Java, dan kelas mixin tidak dapat diimplementasikan menggunakan antarmuka sebagai gantinya. Ini karena antarmuka tidak berisi status, dan keadaan dalam mode pengamat perlu digunakan untuk menyimpan daftar pendengar terdaftar.
Salah satu solusi adalah membuat tipe pendengar Zoolistener yang akan diberitahu ketika hewan meningkat dan berkurang. Kode terlihat seperti ini:
antarmuka publik zoolistener {public void onanimaladded (hewan hewan); public void onanimalremoved (hewan hewan);}Dengan cara ini, Anda dapat menggunakan antarmuka ini untuk mengimplementasikan pemantauan berbagai perubahan dalam keadaan kebun binatang menggunakan tipe pendengar:
ZoousingMixin kelas publik memperluas ObservableSubjectMixin <Imloolistener> {Daftar Privat <En Animal> Hewan = ArrayList baru <> (); public void addanimal (hewan hewan) {// Tambahkan hewan ke daftar hewan yang ada. listener.onanimaladded (hewan));} public void removeAnimal (hewan hewan) {// Lepaskan hewan dari daftar hewan ini.Menggabungkan beberapa jenis pendengar menjadi satu antarmuka pendengar memang menyelesaikan masalah yang disebutkan di atas, tetapi masih ada kekurangan, yang akan dibahas secara rinci dalam bab -bab berikut.
Pendengar dan adaptor multi-metode
Dalam metode di atas, jika antarmuka pendengar menerapkan terlalu banyak fungsi, antarmuka akan terlalu bertele -tele. Misalnya, Swing MouseListener berisi 5 fungsi yang diperlukan. Meskipun Anda hanya dapat menggunakan salah satunya, Anda harus menambahkan 5 fungsi ini selama Anda menggunakan acara klik mouse. Lebih mungkin menggunakan badan fungsi kosong untuk mengimplementasikan fungsi yang tersisa, yang tidak diragukan lagi akan membawa kebingungan yang tidak perlu pada kode.
Salah satu solusi adalah membuat adaptor (konsep berasal dari pola adaptor yang diusulkan oleh GOF). Pengoperasian antarmuka pendengar diimplementasikan dalam bentuk fungsi abstrak untuk pewarisan kelas pendengar tertentu. Dengan cara ini, kelas pendengar spesifik dapat memilih fungsi yang dibutuhkan dan menggunakan operasi default untuk fungsi yang tidak diperlukan oleh adaptor. Misalnya, di kelas Zoolistener dalam contoh di atas, buat Zoooadapter (aturan penamaan adaptor konsisten dengan pendengar, Anda hanya perlu mengubah pendengar dalam nama kelas menjadi adaptor), kode adalah sebagai berikut:
Kelas publik Zoooadapter mengimplementasikan zoolistener {@Overridepublic void onanimaladded (hewan hewan) {} @Overridepublic void onanimalremoved (hewan hewan) {}}Sekilas, kelas adaptor ini tidak signifikan, tetapi kenyamanan yang dibawanya tidak dapat diremehkan. Misalnya, untuk kelas spesifik berikut, cukup pilih fungsi yang berguna bagi mereka:
kelas publik nameprinterzooadapter memperluas zoooadapter {@overridepublic void onanimaladded (hewan hewan) {// cetak nama hewan yang ditambahkan sysystem.out.println ("ditambahkan hewan bernama" + animal.getname ());}}Ada dua alternatif yang juga dapat mengimplementasikan fungsi kelas adaptor: satu adalah menggunakan fungsi default; Yang lainnya adalah menggabungkan antarmuka pendengar dan kelas adaptor ke dalam kelas tertentu. Fungsi default baru diusulkan oleh Java 8, memungkinkan pengembang untuk memberikan metode implementasi default (pertahanan) di antarmuka.
Pembaruan ke perpustakaan Java ini terutama untuk memfasilitasi pengembang untuk mengimplementasikan ekstensi program tanpa mengubah versi lama kode, jadi metode ini harus digunakan dengan hati -hati. Setelah menggunakannya berkali -kali, beberapa pengembang akan merasa bahwa kode yang ditulis dengan cara ini tidak cukup profesional, dan beberapa pengembang berpikir ini adalah fitur Java 8. Tidak peduli apa, mereka perlu memahami apa niat asli dari teknologi ini, dan kemudian memutuskan apakah akan menggunakannya berdasarkan pertanyaan spesifik. Kode antarmuka zoolistener yang diimplementasikan menggunakan fungsi default adalah sebagai berikut:
antarmuka publik zoolistener {default public void onanimaladded (hewani hewan) {} default public void onanimalremoved (hewan hewan) {}}Dengan menggunakan fungsi default, mengimplementasikan kelas -kelas spesifik dari antarmuka tidak perlu menerapkan semua fungsi di antarmuka, tetapi sebaliknya secara selektif mengimplementasikan fungsi yang diperlukan. Meskipun ini adalah solusi yang relatif sederhana untuk masalah ekspansi antarmuka, pengembang harus lebih memperhatikan saat menggunakannya.
Solusi kedua adalah menyederhanakan mode pengamat, menghilangkan antarmuka pendengar, dan menggunakan kelas tertentu untuk mengimplementasikan fungsi pendengar. Misalnya, antarmuka Zoolistener menjadi sebagai berikut:
kelas publik zoolistener {public void onanimaladded (hewan hewan) {} public void onanimalremoved (hewan hewan) {}}Solusi ini menyederhanakan hierarki pola pengamat, tetapi tidak berlaku untuk semua kasus, karena jika antarmuka pendengar digabungkan ke dalam kelas tertentu, pendengar spesifik tidak dapat menerapkan beberapa antarmuka mendengarkan. Misalnya, jika animalAddedListener dan antarmuka yang didengar hewan ditulis dalam kelas konkret yang sama, maka satu pendengar tertentu tidak dapat mengimplementasikan kedua antarmuka secara bersamaan. Selain itu, maksud antarmuka pendengar lebih jelas daripada kelas tertentu. Jelas bahwa yang pertama adalah untuk menyediakan antarmuka untuk kelas lain, tetapi yang terakhir tidak begitu jelas.
Tanpa dokumentasi yang sesuai, pengembang tidak akan tahu bahwa sudah ada kelas yang memainkan peran antarmuka dan mengimplementasikan semua fungsi yang sesuai. Selain itu, nama kelas tidak berisi adaptor karena kelas tidak masuk ke antarmuka tertentu, sehingga nama kelas tidak secara khusus menyiratkan niat ini. Singkatnya, masalah spesifik membutuhkan memilih metode tertentu, dan tidak ada metode yang mahakuasa.
Sebelum kita memulai bab berikutnya, penting untuk menyebutkan bahwa adaptor adalah umum dalam mode pengamatan, terutama dalam versi yang lebih lama dari kode Java. API Swing diimplementasikan berdasarkan adaptor, karena banyak aplikasi lama yang digunakan dalam pola pengamat di Java 5 dan Java 6. Pendengar dalam kasus kebun binatang mungkin tidak memerlukan adaptor, tetapi perlu memahami tujuan adaptor dan aplikasinya, karena kita dapat menggunakannya dalam kode yang ada. Bab berikut akan memperkenalkan pendengar intensif waktu. Jenis pendengar ini dapat melakukan operasi yang memakan waktu atau melakukan panggilan asinkron dan tidak dapat segera memberikan nilai pengembalian.
Pendengar yang kompleks & memblokir
Salah satu asumsi tentang pola pengamat adalah bahwa ketika suatu fungsi dieksekusi, serangkaian pendengar dipanggil, tetapi diasumsikan bahwa proses ini sepenuhnya transparan terhadap penelepon. Misalnya, ketika kode klien menambahkan hewan di kebun binatang, tidak diketahui bahwa serangkaian pendengar akan dipanggil sebelum pengembalian berhasil. Jika eksekusi pendengar membutuhkan waktu lama (waktunya dipengaruhi oleh jumlah pendengar, waktu eksekusi masing -masing pendengar), kode klien akan menyadari efek samping waktu dari peningkatan sederhana dalam operasi hewan ini.
Artikel ini tidak dapat membahas topik ini dengan cara yang komprehensif. Berikut ini adalah hal -hal yang harus diperhatikan oleh pengembang saat memanggil pendengar yang kompleks:
Pendengar memulai utas baru. Setelah utas baru dimulai, saat menjalankan logika pendengar di utas baru, hasil pemrosesan fungsi pendengar dikembalikan dan pendengar lainnya dijalankan.
Subjek memulai utas baru. Tidak seperti iterasi linier tradisional dari daftar pendengar terdaftar, fungsi pemberitahuan subjek me -restart utas baru dan kemudian mengulangi daftar pendengar di utas baru. Ini memungkinkan fungsi Notify untuk menghasilkan nilai pengembaliannya saat melakukan operasi pendengar lainnya. Perlu dicatat bahwa mekanisme keamanan utas diperlukan untuk memastikan bahwa daftar pendengar tidak menjalani modifikasi bersamaan.
Antrian pendengar memanggil dan melakukan fungsi mendengarkan dengan satu set utas. Mengenak operasi pendengar dalam beberapa fungsi dan mengantri mereka alih -alih panggilan iteratif sederhana ke daftar pendengar. Setelah pendengar ini disimpan dalam antrian, utas dapat memunculkan satu elemen dari antrian dan menjalankan logika mendengarkannya. Ini mirip dengan masalah produser-konsumen. Proses Notify menghasilkan antrian fungsi yang dapat dieksekusi, yang kemudian melesat mengambil antrian pada gilirannya dan menjalankan fungsi -fungsi ini. Fungsi perlu menyimpan waktu yang dibuat daripada waktu yang dieksekusi untuk dihubungi oleh fungsi pendengar. Misalnya, fungsi yang dibuat ketika pendengar dipanggil, maka fungsi perlu menyimpan titik waktu. Fungsi ini mirip dengan operasi berikut di Java:
public class AnimalAddedFunctor { private final AnimalAddedListener listener;private final Animal parameter;public AnimalAddedFunctor (AnimalAddedListener listener, Animal parameter) {this.listener = listener;this.parameter = parameter;}public void execute () {// Execute the listener with the parameter provided during creattionThis.listener.updateanimaladded (this.parameter);}}Fungsi dibuat dan disimpan dalam antrian dan dapat dipanggil kapan saja, sehingga tidak perlu melakukan operasi yang sesuai segera ketika melintasi daftar daftar daftar. Setelah setiap fungsi yang mengaktifkan pendengar didorong ke dalam antrian, "utas konsumen" akan mengembalikan hak operasional ke kode klien. "Thread konsumen" akan menjalankan fungsi -fungsi ini di beberapa titik nanti, seperti jika pendengar diaktifkan oleh fungsi notify. Teknologi ini disebut pengikatan parameter dalam bahasa lain, yang hanya sesuai dengan contoh di atas. Inti dari teknologi ini adalah menyimpan parameter pendengar dan kemudian memanggil fungsi eksekusi () secara langsung. Jika pendengar menerima beberapa parameter, metode pemrosesan serupa.
Perlu dicatat bahwa jika Anda ingin menyimpan perintah eksekusi pendengar, Anda perlu memperkenalkan mekanisme penyortiran yang komprehensif. Dalam Skema 1, pendengar mengaktifkan utas baru dalam urutan normal, yang memastikan bahwa pendengar dieksekusi dalam urutan pendaftaran. Dalam Skema 2, antrian mendukung penyortiran, dan fungsi -fungsi di dalamnya akan dieksekusi dalam urutan mereka memasukkan antrian. Sederhananya, pengembang perlu memperhatikan kompleksitas eksekusi pendengar multi-utas dan menanganinya dengan cermat untuk memastikan bahwa mereka menerapkan fungsi yang diperlukan.
Kesimpulan
Sebelum model pengamat ditulis ke dalam buku pada tahun 1994, itu sudah merupakan model desain perangkat lunak utama, memberikan banyak solusi memuaskan untuk masalah yang sering muncul dalam desain perangkat lunak. Java selalu menjadi pemimpin dalam menggunakan pola ini dan merangkum pola ini di perpustakaan standarnya, tetapi mengingat bahwa Java telah diperbarui ke versi 8, sangat penting untuk memeriksa kembali penggunaan pola klasik di dalamnya. Dengan munculnya ekspresi lambda dan struktur baru lainnya, pola "lama" ini telah mengambil vitalitas baru. Apakah itu menangani program lama atau menggunakan metode lama ini untuk menyelesaikan masalah baru, terutama untuk pengembang Java yang berpengalaman, pola pengamat adalah alat utama bagi pengembang.
OnePM memberi Anda solusi kinerja aplikasi Java end-to-end. Kami mendukung semua kerangka kerja Java yang umum dan server aplikasi untuk membantu Anda dengan cepat menemukan kemacetan sistem dan menemukan akar penyebab kelainan. Penempatan pada level kecil dan pengalaman secara instan, pemantauan Java tidak pernah semudah ini. Untuk membaca lebih banyak artikel teknis, silakan kunjungi blog teknologi resmi ONEAPM.
Konten di atas memperkenalkan kepada Anda cara menggunakan Java8 untuk mengimplementasikan mode pengamat (Bagian 2), saya harap ini akan membantu semua orang!