Panduan untuk Antrian Serentak di Jawa

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan membahas beberapa pelaksanaan utama antrian serentak di Jawa. Untuk pengenalan umum mengenai barisan, lihat artikel Panduan Antarmuka Antrian Java kami .

2. Beratur

Dalam aplikasi multithread, barisan perlu menangani pelbagai senario pengeluar-pengguna serentak. Pilihan yang betul dari barisan serentak boleh menjadi penting dalam mencapai prestasi yang baik dalam algoritma kami.

Pertama, kita akan melihat beberapa perbezaan penting antara barisan penyekat dan yang tidak menyekat. Kemudian, kita akan melihat beberapa pelaksanaan dan amalan terbaik.

2. Antrian Sekatan vs Tidak Menyekat

BlockingQueue menawarkan mekanisme keselamatan benang yang mudah . Dalam barisan ini, utas perlu menunggu ketersediaan barisan. Pengeluar akan menunggu kapasiti yang ada sebelum menambahkan elemen, sementara pengguna akan menunggu sehingga barisan kosong. Dalam kes tersebut, barisan yang tidak menyekat akan membuang pengecualian atau mengembalikan nilai khas, seperti null atau false .

Untuk mencapai mekanisme penyekat ini, antara muka BlockingQueue memperlihatkan dua fungsi di atas fungsi Antrian biasa : meletakkan dan mengambil . Fungsi-fungsi tersebut adalah setara dengan menambah dan membuang dalam Antrian standard .

3. Pelaksanaan Antrian Bersamaan

3.1. ArrayBlockingQueue

Seperti namanya, barisan ini menggunakan tatasusunan secara dalaman. Akibatnya, ini adalah barisan terikat, yang bermaksud mempunyai ukuran tetap .

Antrean kerja yang mudah adalah contoh kes penggunaan. Senario ini sering kali merupakan nisbah pengeluar-ke-pengguna yang rendah, di mana kita membahagikan tugas yang memakan masa di antara beberapa pekerja. Oleh kerana barisan ini tidak dapat berkembang tanpa had, had ukuran bertindak sebagai ambang keselamatan sekiranya ingatan menjadi masalah .

Bercakap tentang ingatan, penting untuk diperhatikan bahawa barisan tersebut memperuntukkan array. Walaupun ini dapat meningkatkan throughput, ia juga memakan lebih banyak memori daripada yang diperlukan . Sebagai contoh, barisan berkapasiti besar mungkin kosong untuk jangka masa yang panjang.

Juga, ArrayBlockingQueue menggunakan kunci tunggal untuk operasi meletakkan dan mengambil . Ini memastikan tidak ada penimpaan entri, dengan kos prestasi.

3.2. LinkedBlockingQueue

The LinkedBlockingQueue menggunakan varian LinkedList , di mana setiap item barisan adalah nod baru. Walaupun ini menjadikan antrian tidak terikat pada prinsipnya, ia masih mempunyai had Integer.MAX_VALUE yang sukar .

Sebaliknya, kita dapat menetapkan ukuran antrian dengan menggunakan konstruktor LinkedBlockingQueue (kapasiti int) .

Antrian ini menggunakan kunci yang berbeza untuk operasi meletakkan dan mengambil . Akibatnya, kedua-dua operasi dapat dilakukan secara selari dan meningkatkan throughput.

Oleh kerana LinkedBlockingQueue boleh dibatasi atau tidak terikat, mengapa kita menggunakan ArrayBlockingQueue yang satu ini? LinkedBlockingQueue perlu memperuntukkan dan menyahpindah node setiap kali item ditambahkan atau dikeluarkan dari barisan . Atas sebab ini, ArrayBlockingQueue boleh menjadi alternatif yang lebih baik jika barisan tumbuh dengan cepat dan menyusut dengan cepat.

Prestasi LinkedBlockingQueue dikatakan tidak dapat diramalkan. Dengan kata lain, kita selalu perlu membuat profil senario kita untuk memastikan kita menggunakan struktur data yang betul.

3.3. KeutamaanBlockingQueue

The PriorityBlockingQueue adalah pergi ke penyelesaian kami apabila kita perlu mengambil barangan di dalam susunan yang tertentu . Untuk mencapainya, PriorityBlockingQueue menggunakan timbunan binari berasaskan array.

Walaupun secara internal menggunakan mekanisme kunci tunggal, operasi pengambilan dapat berlaku serentak dengan operasi put . Penggunaan spinlock sederhana menjadikan ini mungkin.

Kes penggunaan biasa adalah memakan tugas dengan keutamaan yang berbeza. Kami tidak mahu tugas dengan keutamaan rendah menggantikan tugas yang mempunyai keutamaan tinggi .

3.4. DelayQueue

Kami menggunakan DelayQueue apabila pengguna hanya dapat mengambil item yang sudah habis masa berlakunya . Menariknya, ia menggunakan PriorityQueue secara dalaman untuk memesan barang-barang tersebut sehingga habis tempohnya.

Oleh kerana ini bukan antrian tujuan umum, ia tidak merangkumi banyak senario seperti ArrayBlockingQueue atau LinkedBlockingQueue . Sebagai contoh, kita boleh menggunakan barisan ini untuk melaksanakan gelung peristiwa sederhana yang serupa dengan yang terdapat di NodeJS. Kami meletakkan tugas tak segerak dalam barisan untuk diproses kemudian apabila tamat.

3.5. LinkedTransferQueue

The LinkedTransferQueue memperkenalkan pemindahan kaedah. Walaupun antrian lain biasanya menyekat ketika menghasilkan atau memakan barang, LinkedTransferQueue membolehkan pengeluar menunggu penggunaan item .

Kami menggunakan LinkedTransferQueue apabila kami memerlukan jaminan bahawa item tertentu yang kami masukkan dalam barisan telah diambil oleh seseorang. Juga, kita dapat menerapkan algoritma tekanan balik sederhana menggunakan barisan ini. Memang, dengan menyekat pengeluar sehingga penggunaan, pengguna dapat mendorong aliran mesej yang dihasilkan .

3.6. Segerak Segera

Walaupun antrian biasanya mengandungi banyak item, SynchronousQueue akan selalu mempunyai, paling banyak, satu item. Dengan kata lain, kita perlu melihat SynchronousQueue sebagai kaedah mudah untuk menukar beberapa data antara dua utas .

Apabila kita mempunyai dua utas yang memerlukan akses ke keadaan bersama, kita sering menyegerakkannya dengan CountDownLatch atau mekanisme penyegerakan lain. Dengan menggunakan SynchronousQueue , kita dapat mengelakkan penyegerakan benang manual ini .

3.7. Bersama-samaLinkedQueue

The ConcurrentLinkedQueue adalah satu-satunya barisan yang tidak menyekat panduan ini. Oleh itu, ia menyediakan algoritma "tunggu-tunggu" di mana penambahan dan tinjauan dijamin selamat untuk dikemas dan dikembalikan dengan segera . Daripada kunci, barisan ini menggunakan CAS (Bandingkan-Dan-Tukar).

Secara dalaman, ia didasarkan pada algoritma dari Algoritma Antrian Tidak Menyekat dan Menyekat Bersamaan, Cepat, dan Praktikal oleh Maged M. Michael dan Michael L. Scott.

Ini adalah calon yang sempurna untuk sistem reaktif moden , di mana penggunaan struktur data menyekat sering dilarang.

Sebaliknya, jika pengguna kita akhirnya menunggu dalam satu pusingan, kita mungkin harus memilih barisan penyekat sebagai alternatif yang lebih baik.

4. Kesimpulan

Dalam panduan ini, kami melalui penerapan antrian serentak yang berbeza, membincangkan kekuatan dan kelemahan mereka. Dengan ini, kami lebih berkemampuan untuk membangunkan sistem yang cekap, tahan lama, dan tersedia.