Pertanyaan saya berkaitan dengan pertanyaan yang diajukan sebelumnya. Dalam situasi di mana saya menggunakan antrean untuk komunikasi antara utas produsen dan konsumen, apakah orang biasanya merekomendasikan penggunaan LinkedBlockingQueue
atau ConcurrentLinkedQueue
?
Apa keuntungan / kerugian menggunakan salah satu dari yang lain?
Perbedaan utama yang dapat saya lihat dari perspektif API adalah bahwa a LinkedBlockingQueue
dapat dibatasi secara opsional.
ConcurrentLinkedQueue
juga berguna jika utas Anda memeriksa beberapa antrian. Misalnya, dalam server multi-tenant. Dengan asumsi untuk alasan isolasi Anda tidak menggunakan satu antrian pemblokiran dan diskriminator penyewa sebagai gantinya.take()
danput()
hanya mengkonsumsi sumber daya tambahan (dalam sinkronisasi) daripadaConcurrentLinkedQueue
. meskipun merupakan kasus untuk menggunakan antrean terbatas untuk skenario Produsen-konsumenPertanyaan ini membutuhkan jawaban yang lebih baik.
Java
ConcurrentLinkedQueue
didasarkan pada algoritme terkenal oleh Maged M. Michael dan Michael L. Scott untuk antrean bebas kunci yang tidak memblokir ."Non-pemblokiran" sebagai istilah di sini untuk sumber daya yang diperebutkan (antrean kami) berarti bahwa apa pun yang dilakukan penjadwal platform, seperti menyela untaian, atau jika untaian yang dipermasalahkan terlalu lambat, untaian lain bersaing untuk sumber daya yang sama akan tetap bisa maju. Jika ada kunci yang terlibat, misalnya, utas yang menahan kunci bisa terputus dan semua utas yang menunggu kunci itu akan diblokir. Kunci intrinsik (
synchronized
kata kunci) di Java juga dapat mengakibatkan hukuman yang berat untuk kinerja - seperti saat penguncian yang biasterlibat dan Anda memang memiliki perselisihan, atau setelah VM memutuskan untuk "memekarkan" kunci setelah masa tenggang putaran dan memblokir utas yang bersaing ... itulah sebabnya dalam banyak konteks (skenario pertengkaran rendah / menengah), melakukan bandingkan-dan -set pada referensi atom bisa jauh lebih efisien dan inilah yang dilakukan oleh banyak struktur data non-pemblokiran.Java
ConcurrentLinkedQueue
bukan hanya non-pemblokiran, tetapi juga memiliki properti luar biasa yang tidak bersaing dengan konsumen oleh produsen. Dalam skenario produsen / konsumen tunggal (SPSC), ini benar-benar berarti bahwa tidak akan ada perselisihan untuk dibicarakan. Dalam skenario banyak produsen / konsumen tunggal, konsumen tidak akan bersaing dengan produsen. Antrean ini memang memiliki perselisihan ketika beberapa produsen mencobaoffer()
, tetapi menurut definisi itu konkurensi. Ini pada dasarnya adalah tujuan umum dan antrian non-pemblokiran yang efisien.Adapun itu bukan
BlockingQueue
, yah, memblokir utas untuk menunggu di antrian adalah cara yang sangat mengerikan untuk merancang sistem bersamaan. Jangan. Jika Anda tidak dapat menemukan cara menggunakan aConcurrentLinkedQueue
dalam skenario konsumen / produsen, beralih saja ke abstraksi tingkat yang lebih tinggi, seperti kerangka aktor yang baik.sumber
LinkedBlockingQueue
memblokir konsumen atau produsen ketika antrian kosong atau penuh dan benang konsumen / produsen masing-masing tertidur. Tetapi fitur pemblokiran ini memiliki biaya: setiap operasi put atau take dikunci antara produsen atau konsumen (jika banyak), jadi dalam skenario dengan banyak produsen / konsumen, operasinya mungkin lebih lambat.ConcurrentLinkedQueue
tidak menggunakan kunci, tetapi CAS , pada operasi put / take-nya berpotensi mengurangi perselisihan dengan banyak utas produsen dan konsumen. Tetapi menjadi struktur data "menunggu bebas",ConcurrentLinkedQueue
tidak akan memblokir ketika kosong, yang berarti bahwa konsumen perlu berurusan dengan nilai-nilai yangtake()
kembalinull
dengan "menunggu sibuk", misalnya, dengan benang konsumen memakan CPU.Jadi mana yang "lebih baik" tergantung pada jumlah benang konsumen, pada tingkat yang mereka konsumsi / produksi, dll. Diperlukan tolok ukur untuk setiap skenario.
Salah satu kasus penggunaan di mana
ConcurrentLinkedQueue
jelas lebih baik adalah ketika produsen pertama kali memproduksi sesuatu dan menyelesaikan pekerjaan mereka dengan menempatkan pekerjaan dalam antrian dan hanya setelah konsumen mulai mengkonsumsi, mengetahui bahwa mereka akan selesai ketika antrian kosong. (di sini tidak ada konkurensi antara produsen-konsumen tetapi hanya antara produsen-produsen dan konsumen-konsumen)sumber
unbounded blockingqueue
digunakan apakah akan lebih baik daripada berbasis CAS secara bersamaanConcurrentLinkedQueue
Solusi lain (yang tidak berskala baik) adalah saluran pertemuan: java.util.concurrent SynchronousQueue
sumber
Jika antrian Anda tidak dapat diperluas dan hanya berisi satu thread produsen / konsumen. Anda dapat menggunakan antrian tanpa kunci (Anda tidak perlu mengunci akses data).
sumber