LinkedBlockingQueue vs ConcurrentLinkedQueue

1. Perkenalan

LinkedBlockingQueue dan ConcurrentLinkedQueue adalah dua antrian bersamaan yang paling sering digunakan di Java . Meskipun kedua antrian sering digunakan sebagai struktur data bersamaan, ada karakteristik halus dan perbedaan perilaku di antara keduanya.

Dalam tutorial singkat ini, kita akan membahas kedua antrian ini dan menjelaskan persamaan dan perbedaannya.

2. LinkedBlockingQueue

The LinkedBlockingQueue adalah opsional-dibatasi memblokir implementasi antrian, yang berarti bahwa ukuran antrian dapat ditentukan jika diperlukan.

Mari buat LinkedBlockingQueue yang dapat berisi hingga 100 elemen:

BlockingQueue boundedQueue = new LinkedBlockingQueue(100);

Kita juga dapat membuat LinkedBlockingQueue tidak terbatas hanya dengan tidak menentukan ukurannya:

BlockingQueue unboundedQueue = new LinkedBlockingQueue();

Antrian tak terbatas menyiratkan bahwa ukuran antrian tidak ditentukan saat membuat. Oleh karena itu, antrean dapat berkembang secara dinamis saat elemen ditambahkan ke dalamnya. Namun, jika tidak ada memori yang tersisa, maka antrian akan menampilkan java.lang.OutOfMemoryError.

Kita juga dapat membuat LinkedBlockingQueue dari koleksi yang ada:

Collection listOfNumbers = Arrays.asList(1,2,3,4,5); BlockingQueue queue = new LinkedBlockingQueue(listOfNumbers);

The LinkedBlockingQueue kelas alat yang BlockingQueue antarmuka, yang menyediakan sifat menghalangi untuk itu .

Antrian pemblokiran menunjukkan bahwa antrian memblokir utas pengakses jika penuh (ketika antrian dibatasi) atau menjadi kosong. Jika antrian penuh, maka menambahkan elemen baru akan memblokir thread yang mengakses kecuali ada ruang yang tersedia untuk elemen baru tersebut. Demikian pula, jika antrian kosong, maka mengakses elemen memblokir thread pemanggil:

ExecutorService executorService = Executors.newFixedThreadPool(1); LinkedBlockingQueue queue = new LinkedBlockingQueue(); executorService.submit(() -> { try { queue.take(); } catch (InterruptedException e) { // exception handling } });

Dalam potongan kode di atas, kami mengakses antrian kosong. Oleh karena itu, metode take memblokir thread pemanggil.

Fitur pemblokiran dari LinkedBlockingQueue dikaitkan dengan sejumlah biaya. Biaya ini karena setiap operasi put atau take dikunci antara benang produsen atau konsumen. Oleh karena itu, dalam skenario dengan banyak produsen dan konsumen, menempatkan dan mengambil tindakan bisa menjadi lebih lambat.

3. ConcurrentLinkedQueue

Sebuah ConcurrentLinkedQueue adalah tak terbatas, benang-aman, dan non-blocking antrian.

Mari buat ConcurrentLinkedQueue kosong :

ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();

Kita juga dapat membuat ConcurrentLinkedQueue dari koleksi yang ada:

Collection listOfNumbers = Arrays.asList(1,2,3,4,5); ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(listOfNumbers);

Tidak seperti LinkedBlockingQueue, sebuah ConcurrentLinkedQueue antrian non-blocking . Dengan demikian, ini tidak memblokir utas setelah antrian kosong. Sebaliknya, ini mengembalikan null . Karena tidak dibatasi, itu akan memunculkan java.lang.OutOfMemoryError jika tidak ada memori tambahan untuk menambahkan elemen baru.

Selain non-blocking, ConcurrentLinkedQueue memiliki fungsi tambahan.

Dalam skenario produsen-konsumen mana pun, konsumen tidak akan puas dengan produsen; namun, beberapa produsen akan bersaing satu sama lain:

int element = 1; ExecutorService executorService = Executors.newFixedThreadPool(2); ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue(); Runnable offerTask = () -> queue.offer(element); Callable pollTask = () -> { while (queue.peek() != null) { return queue.poll().intValue(); } return null; }; executorService.submit(offerTask); Future returnedElement = executorService.submit(pollTask); assertThat(returnedElement.get().intValue(), is(equalTo(element))); 

Tugas pertama, offerTask , menambahkan elemen ke antrean, dan tugas kedua, pollTask, mengambil elemen dari antrean. Tugas polling juga memeriksa antrian untuk elemen terlebih dahulu karena ConcurrentLinkedQueue tidak memblokir dan dapat mengembalikan nilai null .

4. Persamaan

Baik LinkedBlockingQueue maupun ConcurrentLinkedQueue adalah implementasi antrian dan memiliki beberapa karakteristik umum. Mari kita bahas persamaan dari dua antrian ini:

  1. Keduanya mengimplementasikan Antarmuka Antrian
  2. Keduanya menggunakan node tertaut untuk menyimpan elemen mereka
  3. Keduanya cocok untuk skenario akses bersamaan

5. Perbedaan

Meskipun kedua antrean ini memiliki kesamaan tertentu, terdapat juga perbedaan karakteristik yang substansial:

Fitur LinkedBlockingQueue ConcurrentLinkedQueue
Memblokir Alam Ini adalah antrian pemblokiran dan mengimplementasikan antarmuka BlockingQueue Ini adalah antrian non-pemblokiran dan tidak mengimplementasikan antarmuka BlockingQueue
Ukuran Antrian Ini adalah antrian yang dibatasi secara opsional, yang berarti ada ketentuan untuk menentukan ukuran antrian selama pembuatan Ini adalah antrian tidak terbatas, dan tidak ada ketentuan untuk menentukan ukuran antrian selama pembuatan
Mengunci Alam Ini adalah antrian berbasis kunci Ini adalah antrian bebas kunci
Algoritma Ini mengimplementasikan pengunciannya berdasarkan algoritma antrian dua kunci Ini bergantung pada algoritme Michael & Scott untuk antrean tanpa pemblokiran dan bebas kunci
Penerapan Dalam mekanisme algoritme antrean dua kunci , LinkedBlockingQueue menggunakan dua kunci berbeda - putLock dan takeLock . Operasi put / take menggunakan tipe kunci pertama, dan operasi take / poll menggunakan tipe kunci lainnya Ia menggunakan CAS (Compare-And-Swap ) untuk operasinya
Memblokir Perilaku Ini adalah antrian pemblokiran. Jadi, ini memblokir utas pengakses saat antrian kosong Itu tidak memblokir utas pengakses ketika antrian kosong dan mengembalikan null

6. Kesimpulan

Di artikel ini, kita belajar tentang LinkedBlockingQueue dan ConcurrentLinkedQueue.

Pertama, kami secara individu membahas dua implementasi antrian ini dan beberapa karakteristiknya. Kemudian, kami melihat kesamaan antara dua implementasi antrian ini. Akhirnya, kami menjelajahi perbedaan antara dua implementasi antrian ini.

Seperti biasa, kode sumber contoh tersedia di GitHub.