Antrian Tanpa Pemblokiran

Implementasi Antrean yang aman untuk thread dan yang paling penting non-pemblokiran pada node yang ditautkan.

ConcurrentLinkedQueue<E> - ini menggunakan algoritme bebas tunggu yang diadaptasi untuk bekerja dengan pengumpul sampah. Algoritma ini cukup efisien dan sangat cepat, karena dibangun di atas CAS. Metode size() dapat berjalan untuk waktu yang lama, jadi sebaiknya jangan menariknya sepanjang waktu.

ConcurrentLinkedDeque<E> - Deque adalah singkatan dari Antrean ujung ganda. Ini berarti bahwa data dapat ditambahkan dan ditarik dari kedua sisi. Dengan demikian, kelas mendukung kedua mode operasi: FIFO (First In First Out) dan LIFO (Last In First Out).

Dalam praktiknya, ConcurrentLinkedDeque harus digunakan jika LIFO benar-benar diperlukan, karena karena node dua arah, kelas ini kehilangan separuh kinerjanya dibandingkan dengan ConcurrentLinkedQueue .

import java.util.concurrent.ConcurrentLinkedQueue;

public class  ConcurrentLinkedQueueExample {
   public static void main(String[] args) {
       ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();

       Thread producer = new Thread(new Producer(queue));
       Thread consumer = new Thread(new Consumer(queue));

       producer.start();
       consumer.start();
   }
}

class Producer implements Runnable {

   ConcurrentLinkedQueue<String> queue;
   Producer(ConcurrentLinkedQueue<String> queue){
       this.queue = queue;
   }
   public void run() {
       System.out.println("Class for adding items to the queue");
       try {
           for (int i = 1; i < 5; i++) {
               queue.add("Item #" + i);
               System.out.println("Added: Item #" + i);
               Thread.sleep(300);
           }
       } catch (InterruptedException ex) {
           ex.printStackTrace();
           Thread.currentThread().interrupt();
       }
   }
}

class Consumer implements Runnable {

   ConcurrentLinkedQueue<String> queue;
   Consumer(ConcurrentLinkedQueue<String> queue){
       this.queue = queue;
   }

   public void run() {
       String str;
       System.out.println("Class for getting items from the queue");
       for (int x = 0; x < 5; x++) {
           while ((str = queue.poll()) != null) {
               System.out.println("Pulled out: " + str);
           }
           try {
               Thread.sleep(600);
           } catch (InterruptedException ex) {
               ex.printStackTrace();
               Thread.currentThread().interrupt();
           }
       }
   }
}

Memblokir Antrian

Antarmuka BlockingQueue<E> - jika ada banyak data, ConcurrentLinkedQueue tidak cukup.

Ketika utas gagal melakukan tugasnya, Anda dapat dengan mudah mendapatkan OutOfMemmoryException . Dan agar kasus seperti itu tidak muncul, kami memiliki BlockingQueue untuk bekerja dengan adanya berbagai metode untuk mengisi dan bekerja dengan antrian dan kunci bersyarat.

BlockingQueue tidak mengenali elemen nol dan melempar NullPointerException saat mencoba menambah atau mendapatkan elemen seperti itu. Metode polling mengembalikan elemen nol jika tidak ada elemen yang ditempatkan dalam antrean dalam batas waktu.

Implementasi BlockingQueue<E>

Mari kita lihat lebih dekat masing-masing implementasi BlockingQueue kami :

ArrayBlockingQueue<E> adalah kelas antrian pemblokiran yang dibangun di atas buffer cincin klasik. Di sini kita memiliki kesempatan untuk mengelola "kejujuran" kunci. Jika fair=false (default), maka pengurutan utas tidak dijamin.

DelayQueue<E extends Delayed> adalah kelas yang memungkinkan Anda menarik elemen dari antrean hanya setelah penundaan tertentu, yang ditentukan di setiap elemen melalui metode getDelay dari antarmuka Delayed .

LinkedBlockingQueue<E> adalah antrean pemblokiran pada node tertaut, diimplementasikan pada algoritme "dua kunci antrean": kunci pertama untuk penambahan, kunci kedua untuk menarik elemen dari antrean. Karena penguncian, dibandingkan dengan ArrayBlockingQueue , kelas ini memiliki performa tinggi, tetapi membutuhkan lebih banyak memori. Ukuran antrean diatur melalui konstruktor dan sama dengan Integer.MAX_VALUE secara default.

PriorityBlockingQueue<E> adalah pembungkus multi-utas di atas PriorityQueue . Comparator bertanggung jawab atas logika dimana elemen akan ditambahkan. Elemen terkecil keluar lebih dulu.

SynchronousQueue<E> - antrian bekerja sesuai dengan prinsip FIFO (first-in-first-out). Setiap operasi penyisipan memblokir utas "Produser" hingga utas "Konsumen" menarik elemen dari antrean dan sebaliknya, "Konsumen" akan menunggu hingga "Produser" memasukkan elemen.

BlockingDeque<E> adalah antarmuka yang menjelaskan metode tambahan untuk antrian pemblokiran dua arah. Data dapat dimasukkan dan ditarik keluar dari kedua sisi antrian.

LinkedBlockingDeque<E> adalah antrian pemblokiran dua arah pada node tertaut, diimplementasikan sebagai daftar dua arah sederhana dengan satu kunci. Ukuran antrean diatur melalui konstruktor dan sama dengan Integer.MAX_VALUE secara default.

TransferQueue<E> - antarmuka menarik karena ketika elemen ditambahkan ke antrean, dimungkinkan untuk memblokir utas Produser yang dimasukkan hingga utas Konsumen lain menarik elemen dari antrean. Anda juga dapat menambahkan tanda centang untuk batas waktu tertentu atau mengatur tanda centang untuk Konsumen yang tertunda . Hasilnya, kami mendapatkan mekanisme transfer data dengan dukungan untuk pesan asinkron dan sinkron.

LinkedTransferQueue<E> adalah implementasi dari TransferQueue berdasarkan algoritma Dual Queues with Slack. Banyak menggunakan CAS (lihat di atas) dan thread parking saat idle.