Dari JavaDocs:
- Sebuah ConcurrentLinkedQueue adalah pilihan yang tepat ketika banyak benang akan berbagi akses ke koleksi umum. Antrian ini tidak mengizinkan elemen nol.
- ArrayBlockingQueue adalah "buffer terbatas" klasik, di mana array berukuran tetap menampung elemen yang dimasukkan oleh produsen dan diekstraksi oleh konsumen. Kelas ini mendukung kebijakan kewajaran opsional untuk memesan utas produsen dan konsumen yang menunggu
- LinkedBlockingQueue biasanya memiliki throughput yang lebih tinggi daripada antrian berbasis array tetapi kinerja yang kurang dapat diprediksi di sebagian besar aplikasi bersamaan.
Saya punya 2 skenario, satu membutuhkan antrian untuk mendukung banyak produsen (utas menggunakannya) dengan satu konsumen dan yang lainnya adalah sebaliknya.
Saya tidak mengerti implementasi mana yang digunakan. Adakah yang bisa menjelaskan perbedaannya?
Juga, apa 'kebijakan keadilan opsional' di ArrayBlockingQueue
?
java
multithreading
concurrency
queue
David Hofmann
sumber
sumber
Jawaban:
Pada dasarnya perbedaan di antara mereka adalah karakteristik kinerja dan perilaku memblokir.
Mengambil yang termudah dulu,
ArrayBlockingQueue
adalah antrian dengan ukuran tetap. Jadi, jika Anda menetapkan ukuran pada 10, dan mencoba untuk memasukkan elemen ke-11, pernyataan menyisipkan akan memblokir sampai utas lain menghapus elemen. Masalah keadilan adalah apa yang terjadi jika beberapa utas mencoba menyisipkan dan menghapus pada saat yang sama (dengan kata lain selama periode ketika Antrian diblokir). Algoritma keadilan memastikan bahwa utas pertama yang meminta adalah utas pertama yang didapat. Jika tidak, utas yang diberikan mungkin menunggu lebih lama dari utas lainnya, menyebabkan perilaku yang tidak dapat diprediksi (kadang-kadang satu utas hanya akan memakan waktu beberapa detik karena utas lain yang mulai kemudian diproses terlebih dahulu). Imbalannya adalah dibutuhkan overhead untuk mengelola keadilan, memperlambat throughput.Perbedaan paling penting antara
LinkedBlockingQueue
danConcurrentLinkedQueue
adalah bahwa jika Anda meminta elemen dari aLinkedBlockingQueue
dan antriannya kosong, utas Anda akan menunggu sampai ada sesuatu di sana. AConcurrentLinkedQueue
akan segera kembali dengan perilaku antrian kosong.Yang mana tergantung pada apakah Anda membutuhkan pemblokiran. Di mana Anda memiliki banyak produsen dan satu konsumen, kedengarannya seperti itu. Di sisi lain, di mana Anda memiliki banyak konsumen dan hanya satu produsen, Anda mungkin tidak memerlukan perilaku pemblokiran, dan mungkin senang jika konsumen memeriksa apakah antriannya kosong dan beralih jika ada.
sumber
ConcurrentLinkedQueue berarti tidak ada kunci yang diambil (yaitu tidak ada panggilan yang disinkronkan (ini) atau Lock.lock ). Ini akan menggunakan operasi CAS - Compare dan Swap selama modifikasi untuk melihat apakah head / tail node masih sama seperti ketika dimulai. Jika demikian, operasi berhasil. Jika simpul kepala / ekor berbeda, ia akan berputar dan mencoba lagi.
LinkedBlockingQueue akan mengunci sebelum ada modifikasi. Jadi panggilan penawaran Anda akan diblokir sampai mereka mendapatkan kunci. Anda dapat menggunakan kelebihan penawaran yang membutuhkan TimeUnit untuk mengatakan Anda hanya bersedia menunggu jumlah X sebelum meninggalkan add (biasanya baik untuk antrian jenis pesan di mana pesan basi setelah X jumlah milidetik).
Keadilan berarti bahwa implementasi Kunci akan menjaga utas tetap teratur. Berarti jika Thread A masuk dan kemudian Thread B masuk, Thread A akan mendapatkan kunci terlebih dahulu. Tanpa keadilan, tidak dapat ditentukan apa yang sebenarnya terjadi. Kemungkinan besar akan menjadi utas berikutnya yang dijadwalkan.
Adapun yang digunakan, itu tergantung. Saya cenderung menggunakan ConcurrentLinkedQueue karena waktu yang dibutuhkan produsen saya untuk mendapatkan pekerjaan untuk dimasukkan ke dalam antrian sangat beragam. Saya tidak memiliki banyak produsen yang memproduksi pada saat yang bersamaan. Tapi sisi konsumen lebih rumit karena jajak pendapat tidak akan masuk ke kondisi tidur yang baik. Anda harus mengatasinya sendiri.
sumber
Judul pertanyaan Anda menyebutkan Antrian Pemblokiran. Namun,
ConcurrentLinkedQueue
ini bukan antrian pemblokiran.The
BlockingQueue
s adalahArrayBlockingQueue
,DelayQueue
,LinkedBlockingDeque
,LinkedBlockingQueue
,PriorityBlockingQueue
, danSynchronousQueue
.Beberapa ini adalah jelas tidak cocok untuk tujuan Anda (
DelayQueue
,PriorityBlockingQueue
, danSynchronousQueue
).LinkedBlockingQueue
danLinkedBlockingDeque
identik, kecuali bahwa yang terakhir adalah Antrian berujung ganda (ini mengimplementasikan antarmuka Deque).Karena
ArrayBlockingQueue
hanya berguna jika Anda ingin membatasi jumlah elemen, saya akan tetap melakukannyaLinkedBlockingQueue
.sumber
ArrayBlockingQueue memiliki jejak memori yang lebih rendah, dapat menggunakan kembali elemen node, tidak seperti LinkedBlockingQueue yang harus membuat objek $ Node LinkedBlockingQueue untuk setiap penyisipan baru.
sumber
ArrayBlockingQueue
akan memiliki jejak memori yang jauh lebih buruk - ia masih memiliki array besar yang dialokasikan dalam memori sepanjang waktu, sementara yangLinkedBlockingQueue
akan memiliki jejak memori diabaikan ketika dekat dengan kosong.SynchronousQueue
(Diambil dari pertanyaan lain )SynchronousQueue
lebih merupakan handoff, sedangkan yangLinkedBlockingQueue
adil memungkinkan satu elemen. Perbedaannya adalah bahwaput()
panggilan ke aSynchronousQueue
tidak akan kembali sampai adatake()
panggilan yang sesuai , tetapi denganLinkedBlockingQueue
ukuran 1,put()
panggilan (ke antrian kosong) akan segera kembali. Ini pada dasarnyaBlockingQueue
implementasi ketika Anda benar-benar tidak ingin antrian (Anda tidak ingin mempertahankan data yang tertunda).LinkedBlockingQueue
(LinkedList
Implementasi tetapi Tidak Tepat. Implementasi JDKLinkedList
menggunakan Node kelas internal statis untuk menjaga Link antar elemen)Konstruktor untuk LinkedBlockingQueue
Kelas Node Digunakan untuk Memelihara Tautan
3. ArrayBlockingQueue (Implementasi Array)
Konstruktor untuk ArrayBlockingQueue
IMHO Perbedaan terbesar antara
ArrayBlockingQueue
danLinkedBlockingQueue
jelas dari konstruktor satu memiliki struktur data yang mendasari Array dan linkedList lainnya .ArrayBlockingQueue
menggunakan algoritma kondisi ganda tunggal-kunci danLinkedBlockingQueue
merupakan varian dari algoritma "dua kunci antrian" dan memiliki 2 kondisi 2 kunci (takeLock, putLock)sumber
ConcurrentLinkedQueue bebas kunci, LinkedBlockingQueue tidak. Setiap kali Anda mengaktifkan LinkedBlockingQueue.put () atau LinkedBlockingQueue.take (), Anda harus mendapatkan kunci terlebih dahulu. Dengan kata lain, LinkedBlockingQueue memiliki konkurensi yang buruk. Jika Anda peduli kinerja, coba ConcurrentLinkedQueue + LockSupport.
sumber