LinkedBlockingQueue vs ConcurrentLinkedQueue

1. Pengenalan

LinkedBlockingQueue dan ConcurrentLinkedQueue adalah dua barisan serentak yang paling kerap digunakan di Java . Walaupun kedua-dua barisan sering digunakan sebagai struktur data serentak, terdapat ciri-ciri halus dan perbezaan tingkah laku di antara mereka.

Dalam tutorial ringkas ini, kita akan membincangkan kedua-dua barisan ini dan menerangkan persamaan dan perbezaannya.

2. LinkedBlockingQueue

The LinkedBlockingQueue adalah pilihan-disempadani menyekat pelaksanaan giliran, yang bermaksud bahawa saiz barisan boleh ditentukan jika diperlukan.

Mari buat LinkedBlockingQueue yang boleh mengandungi hingga 100 elemen:

BlockingQueue boundedQueue = new LinkedBlockingQueue(100);

Kami juga dapat membuat LinkedBlockingQueue yang tidak terikat hanya dengan tidak menentukan ukuran:

BlockingQueue unboundedQueue = new LinkedBlockingQueue();

Antrean tanpa had menunjukkan bahawa ukuran barisan tidak ditentukan semasa membuat. Oleh itu, barisan boleh tumbuh secara dinamik apabila elemen ditambahkan ke dalamnya. Walau bagaimanapun, jika tidak ada memori yang tersisa, maka barisan melemparkan ralat java.lang.OutOfMemoryError.

Kita boleh membuat LinkedBlockingQueue dari koleksi yang ada juga:

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

The LinkedBlockingQueue kelas alat yang BlockingQueue antara muka, yang menyediakan sifat menyekat ia .

Antrian yang menyekat menunjukkan bahawa barisan menyekat utas akses jika penuh (ketika barisan dibatasi) atau menjadi kosong. Sekiranya barisan penuh, maka menambahkan elemen baru akan menyekat utas masuk melainkan ada ruang yang tersedia untuk elemen baru. Begitu juga, jika barisan kosong, maka mengakses elemen menyekat utas panggilan:

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

Dalam coretan kod di atas, kami mengakses barisan kosong. Oleh itu, kaedah pengambilan menyekat urutan panggilan.

Ciri penyekat LinkedBlockingQueue dikaitkan dengan beberapa kos. Kos ini adalah kerana setiap operasi meletakkan atau mengambil kunci adalah antara benang pengeluar atau pengguna. Oleh itu, dalam senario dengan banyak pengeluar dan pengguna, meletakkan dan mengambil tindakan yang boleh menjadi lebih perlahan.

3. Bersama Bersambung

A ConcurrentLinkedQueue adalah kurnia yang amat besar, benang selamat, dan beratur bukan menyekat.

Mari buat ConcurrentLinkedQueue kosong :

ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();

Kita boleh membuat ConcurrentLinkedQueue dari koleksi yang ada juga:

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

Tidak seperti LinkedBlockingQueue, yang ConcurrentLinkedQueue ialah barisan bukan menyekat . Oleh itu, ia tidak menyekat utas setelah barisan kosong. Sebaliknya, ia mengembalikan nol . Oleh kerana tidak terikat, ia akan membuang kesalahan java.lang.OutOfMemoryError jika tidak ada memori tambahan untuk menambahkan elemen baru.

Selain tidak menyekat, ConcurrentLinkedQueue mempunyai fungsi tambahan.

Dalam senario pengeluar-pengguna, pengguna tidak akan berpuas hati dengan pengeluar; namun, beberapa pengeluar akan bersaing antara 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 dalam barisan, dan tugas kedua, pollTask, mengambil elemen dari barisan. Tugas tinjauan juga memeriksa antrian untuk elemen terlebih dahulu kerana ConcurrentLinkedQueue tidak menyekat dan dapat mengembalikan nilai nol .

4. Persamaan

Kedua-dua LinkedBlockingQueue dan ConcurrentLinkedQueue adalah barisan pelaksanaan dan berkongsi beberapa ciri-ciri yang sama. Mari kita bincangkan persamaan kedua-dua barisan ini:

  1. Kedua-duanya menggunakan Antarmuka Antrian
  2. Mereka berdua menggunakan nod terpaut untuk menyimpan elemen mereka
  3. Kedua- duanya sesuai untuk senario akses serentak

5. Perbezaan

Walaupun kedua-dua barisan ini mempunyai persamaan tertentu, terdapat juga perbezaan ciri yang besar:

Ciri LinkedBlockingQueue BersamaanLinkedQueue
Menyekat Alam Ini adalah barisan blok dan menerapkan antara muka BlockingQueue Ini adalah antrian yang tidak menyekat dan tidak melaksanakan antara muka BlockingQueue
Saiz Antrian Ini adalah antrian yang dibatasi secara opsional, yang bermaksud ada ketentuan untuk menentukan ukuran antrian semasa pembuatan Ini adalah barisan tanpa batas, dan tidak ada peruntukan untuk menentukan ukuran barisan semasa pembuatan
Mengunci Alam Ini adalah barisan berasaskan kunci Ini adalah barisan bebas kunci
Algoritma Ia melaksanakan pengunciannya berdasarkan algoritma antrian dua kunci Ia bergantung pada algoritma Michael & Scott untuk antrian yang tidak menyekat dan bebas kunci
Pelaksanaan Dalam mekanisme algoritma queue dua kunci , LinkedBlockingQueue menggunakan dua kunci berbeza - putLock dan takeLock . Operasi put / take menggunakan jenis kunci pertama, dan operasi pengambilan / undian menggunakan jenis kunci yang lain Ia menggunakan CAS (Bandingkan-Dan-Tukar ) untuk operasinya
Menyekat Tingkah Laku Ini adalah barisan penyekat. Jadi, ia menyekat kemasukan utas apabila barisan kosong Itu tidak menyekat utas akses ketika barisan kosong dan kembali kosong

6. Kesimpulannya

Dalam artikel ini, kami belajar mengenai LinkedBlockingQueue dan ConcurrentLinkedQueue.

Pertama, kita secara individu membincangkan kedua-dua pelaksanaan antrian ini dan beberapa ciri mereka. Kemudian, kami melihat persamaan antara kedua implementasi antrian ini. Akhirnya, kami meneroka perbezaan antara kedua implementasi antrian ini.

Seperti biasa, kod sumber contoh boleh didapati di GitHub.