Ketika datang ke Java NIO (input/output baru), ia adalah satu set API Java yang kuat yang menyediakan sistem I/O yang berorientasikan penampan, tidak menyekat. Sebagai pembekal NIO, saya telah menyaksikan secara langsung pelbagai kesilapan biasa yang dibuat oleh pemaju ketika menggunakan Java Nio. Dalam catatan blog ini, saya akan menyelidiki kesilapan -kesilapan ini dan menawarkan pandangan tentang cara mengelakkannya.
1. Salah faham sifat bukan menyekat
Salah satu konsep yang paling asas dalam Java Nio adalah sifatnya yang tidak menyekat. Walau bagaimanapun, ramai pemaju salah faham konsep ini. Dalam I/O tradisional, operasi seperti membaca dari soket atau fail menyekat, yang bermaksud benang ditangguhkan sehingga operasi selesai. Sebaliknya, Java Nio membolehkan benang melakukan tugas lain sambil menunggu operasi I/O selesai.
Kesilapan yang sama adalah menggunakan saluran bukan menyekat dengan cara yang menafikan kelebihan mereka. Sebagai contoh, sesetengah pemaju mungkin menulis kod yang sentiasa mengundi saluran bukan menyekat untuk memeriksa sama ada data tersedia. Ini boleh membawa kepada penggunaan CPU yang tinggi kerana benang terus berjalan dalam gelung yang ketat, memakan sumber walaupun tidak ada data baru.
import java.nio.channels.socketchannel; import java.io.ioException; kelas awam BadnonBlockingExample {public static void main (string [] args) melemparkan ioException {socketchannel channel = socketchannel.open (); Channel.ConfigureBlocking (palsu); sementara (benar) {if (channel.read (null)> 0) {// data proses}}}}
Untuk mengelakkan kesilapan ini, pemaju harus menggunakanPemilihDi Java Nio. APemilihMembolehkan satu benang untuk memantau pelbagai saluran untuk pelbagai acara sepertiOp_read,OP_WRITE, dan lain -lain. Dengan cara ini, benang boleh menunggu dengan cekap sehingga peristiwa berlaku di salah satu saluran berdaftar.


import java.nio.channels.socketchannel; import java.nio.channels.selector; import java.nio.channels.SelectionKey; import java.io.ioException; import java.util.iterator; kelas awam GoodNonBlockingExample {public static void main (string [] args) melemparkan ioException {socketchannel channel = socketchannel.open (); Channel.ConfigureBlocking (palsu); Pemilih pemilih = selector.Open (); channel.register (pemilih, pilihanKey.op_read); sementara (benar) {selector.Select (); Iterator <pecstionKey> kekunci = selector.selectedKeys (). Iterator (); manakala (kekunci.HasNext ()) {pemilihan kunci = kunci.next (); jika (key.isReadable ()) {// Data Proses} kunci.remove (); }}}}
2. Pengurusan Buffer yang tidak betul
Buffer berada di teras Java Nio. Mereka digunakan untuk menyimpan data yang dibaca dari saluran atau data yang akan ditulis ke saluran. Satu kesilapan biasa adalah pengurusan penampan yang tidak betul, terutamanya mengenaikedudukan,had, dankapasitipenampan.
Thekapasitipenampan adalah bilangan maksimum elemen yang boleh dipegangnya. ThekedudukanMenunjukkan lokasi semasa di mana elemen seterusnya akan dibaca atau ditulis, danhadadalah indeks selepas elemen yang sah terakhir.
Pemaju sering lupa untuk membalikkan penampan selepas menulis data ke dalamnya sebelum membaca. TheFlip ()kaedah menetapkanhadkepada aruskedudukandan kemudian menetapkan semulakedudukankepada 0. Tanpa membalikkan penampan, operasi bacaan akan bermula dari akhir data yang hanya ditulis, yang membawa kepada hasil yang tidak dijangka.
import java.nio.bytebuffer; kelas awam BuffermanagementMistake {public static void main (string [] args) {bytebuffer buffer = bytebuffer.allocate (1024); Data String = "Hello, Java Nio!"; buffer.put (data.getBytes ()); // kesilapan: tidak memanggil flip () byte [] result = byte baru [buffer.capacity ()]; buffer.get (hasil); System.out.println (rentetan baru (hasil)); }}
Cara yang betul adalah memanggilFlip ()Sebelum membaca dari penampan.
import java.nio.bytebuffer; kelas awam CorrectBuffermanagement {public static void main (string [] args) {bytebuffer buffer = bytebuffer.allocate (1024); Data String = "Hello, Java Nio!"; buffer.put (data.getBytes ()); buffer.flip (); byte [] result = byte baru [buffer.remaining ()]; buffer.get (hasil); System.out.println (rentetan baru (hasil)); }}
Kesalahan lain yang berkaitan tidak membersihkan atau memadatkan penampan apabila ia tidak lagi diperlukan. Gagal berbuat demikian boleh menyebabkan kebocoran memori, terutamanya dalam aplikasi yang panjang.
3. Mengabaikan pengendalian pengecualian
Pengendalian pengecualian adalah penting dalam mana -mana pengaturcaraan, dan Java Nio tidak terkecuali. Walau bagaimanapun, banyak pemaju mengabaikan pengendalian pengecualian yang betul apabila bekerja dengan saluran dan pemilih Java Nio.
Semasa bekerja dengan saluran rangkaian, sebagai contoh, pelbagai pengecualian boleh berlaku, sepertiIoExceptionApabila terdapat ralat rangkaian atauTertutupChannelExceptionApabila saluran sudah ditutup. Mengabaikan pengecualian ini boleh membawa kepada masalah yang sukar - untuk - debug dalam permohonan.
import java.nio.channels.socketchannel; import java.io.ioException; kelas awam noExceptionHandling {public static void main (string [] args) {try {socketchannel channel = socketchannel.open (); // beberapa operasi} menangkap (pengecualian e) {// tiada pengendalian yang betul}}}
Pemaju harus mengendalikan pengecualian dengan anggun. Contohnya, jikaIoExceptionBerlaku semasa membaca dari saluran, aplikasi boleh log ralat, menutup saluran dengan betul, dan mengambil tindakan pemulihan yang sesuai.
import java.nio.channels.socketchannel; import java.io.ioException; import java.util.logging.level; import java.util.logging.logger; kelas awam propereExceptionHandling {logger final static swasta = logger.getLogger (propereExceptionHandling.class.getName ()); public static void main (string [] args) {try {socketchannel channel = socketchannel.Open (); // beberapa operasi} menangkap (ioException e) {logger.log (level.severe, "ioException berlaku:", e); // Tutup saluran dan lakukan tindakan pemulihan}}}
4. Tidak mempertimbangkan keselamatan benang
Saluran dan pemilih Java Nio tidak selalu benang - selamat. Sebagai contoh, jika beberapa benang cuba mendaftarkan saluran dengan pemilih secara serentak, ia boleh membawa kepada keadaan perlumbaan.
Pemaju perlu memastikan penyegerakan yang betul apabila mengakses sumber NIO yang dikongsi. Salah satu cara untuk melakukan ini adalah dengan menggunakan kunci. Walau bagaimanapun, penggunaan kunci yang berlebihan juga boleh menyebabkan kemerosotan prestasi.
import java.nio.channels.socketchannel; import java.nio.channels.selector; import java.nio.channels.SelectionKey; import java.io.ioException; import java.util.concurrent.locks.lock; import java.util.concurrent.locks.reentrantlock; kelas awam ThreadSafetyExample {kunci akhir statik peribadi kunci = reentRantLock baru (); pemilih pemilih statik peribadi; public static void main (string [] args) melemparkan ioException {selector = selector.Open (); Thread t1 = thread baru (() -> {try {socketchannel channel = socketchannel.open (); lock.lock (); cuba {channel.register (selector, pilihanKey.op_read);} akhirnya {lock.unlock (); Thread t2 = thread baru (() -> {try {socketchannel channel = socketchannel.open (); lock.lock (); cuba {channel.register (selector, pilihanKey.op_read);} akhirnya {lock.unlock (); t1.start (); t2.start (); }}
5. Menghadapi skalabiliti
Java Nio direka untuk berskala, terutamanya dalam aplikasi yang tinggi dan rendah. Walau bagaimanapun, sesetengah pemaju mengabaikan skalabiliti apabila mereka bentuk aplikasi mereka.
Sebagai contoh, jika aplikasi menggunakan benang tunggal untuk mengendalikan sejumlah besar saluran, ia boleh menjadi kesesakan. Dalam kes sedemikian, pemaju harus mempertimbangkan menggunakan kolam thread untuk mengedarkan beban kerja di antara pelbagai benang.
import java.nio.channels.socketchannel; import java.nio.channels.selector; import java.nio.channels.SelectionKey; import java.io.ioException; import java.util.concurrent.executorservice; import java.util.concurrent.executors; Kelas Awam Kelas Skalabiliti {private static final int thread_pool_size = 10; Executor ExecutorService Final Static Private = Executors.NewFixedThreadPool (thread_pool_size); public static void main (string [] args) melemparkan ioException {selector selector = selector.Open (); // Saluran mendaftar sementara (benar) {selector.Select (); untuk (pemilihan kunci: selector.selectedKeys ()) {executor.submit () -> {if (key.isReadable ()) {// Data Proses}}); }}}}
Kesimpulan
Sebagai pembekal NIO, saya memahami pentingnya menggunakan Java NIO dengan betul. Dengan mengelakkan kesilapan biasa ini, pemaju boleh membina aplikasi yang lebih cekap, boleh dipercayai, dan berskala. Jika anda berminat untuk mempelajari lebih lanjut mengenai Java Nio atau mencari komponen NIO yang berkualiti tinggi, kami berada di sini untuk membantu. Kami boleh menawarkan nasihat profesional dan penyelesaian yang disesuaikan dengan keperluan khusus anda. Sama ada anda sedang menjalankan projek skala kecil atau aplikasi perusahaan yang besar, kepakaran kami di NIO boleh membuat perbezaan yang signifikan.
Sekiranya anda juga berminat dengan kereta elektrik, anda boleh melihatKereta elektrik nio et5.
Sekiranya anda mempunyai sebarang pertanyaan atau bersedia untuk memulakan perbincangan perolehan, jangan ragu untuk menghubungi kami. Kami berharap dapat bekerjasama dengan anda untuk mencapai matlamat projek anda.
Rujukan
- "Java Nio" oleh Ron Hitchens
- Dokumentasi Oracle Java di NIO



























































