Baris Tidak Menyekat

Pelaksanaan Baris Gilir yang selamat untuk benang dan paling penting tidak menyekat pada nod terpaut.

ConcurrentLinkedQueue<E> - ia menggunakan algoritma tanpa menunggu yang disesuaikan untuk berfungsi dengan pemungut sampah. Algoritma ini agak cekap dan sangat pantas, kerana ia dibina di atas CAS. Kaedah size() boleh berjalan untuk masa yang lama, jadi sebaiknya jangan tariknya sepanjang masa.

ConcurrentLinkedDeque<E> - Deque adalah singkatan kepada baris gilir Berganda. Ini bermakna data boleh ditambah dan ditarik dari kedua-dua belah pihak. Sehubungan itu, kelas menyokong kedua-dua mod operasi: FIFO (Masuk Dahulu Keluar) dan LIFO (Masuk Dahulu Terakhir).

Dalam amalan, ConcurrentLinkedDeque harus digunakan jika LIFO benar-benar diperlukan, kerana disebabkan kedwiarah nod, kelas ini kehilangan separuh dalam prestasi berbanding 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();
           }
       }
   }
}

Menyekat Baris

Antara muka BlockingQueue<E> - jika terdapat banyak data, ConcurrentLinkedQueue tidak mencukupi.

Apabila benang gagal melakukan tugasnya, anda boleh mendapatkan OutOfMemmoryException dengan mudah . Dan supaya kes sedemikian tidak timbul, kami mempunyai BlockingQueue untuk bekerja dengan kehadiran kaedah yang berbeza untuk mengisi dan bekerja dengan baris gilir dan kunci bersyarat.

BlockingQueue tidak mengenali unsur null dan membuang NullPointerException apabila cuba menambah atau mendapatkan elemen sedemikian. Kaedah tinjauan pendapat mengembalikan elemen nol jika tiada elemen diletakkan dalam baris gilir dalam masa tamat.

Perlaksanaan BlockingQueue<E>

Mari kita lihat dengan lebih dekat setiap pelaksanaan BlockingQueue kami :

ArrayBlockingQueue<E> ialah kelas baris gilir menyekat yang dibina pada penimbal cincin klasik. Di sini kita mempunyai peluang untuk menguruskan "kejujuran" kunci. Jika adil=false (lalai), maka urutan urutan tidak dijamin.

DelayQueue<E extends Delayed> ialah kelas yang membolehkan anda menarik elemen daripada baris gilir hanya selepas kelewatan tertentu, ditakrifkan dalam setiap elemen melalui kaedah getDelay antara muka Tertunda .

LinkedBlockingQueue<E> ialah baris gilir menyekat pada nod terpaut, dilaksanakan pada algoritma "baris gilir dua kunci": kunci pertama adalah untuk menambah, yang kedua adalah untuk menarik elemen daripada baris gilir. Disebabkan oleh kunci, berbanding dengan ArrayBlockingQueue , kelas ini mempunyai prestasi tinggi, tetapi memerlukan lebih banyak memori. Saiz baris gilir ditetapkan melalui pembina dan bersamaan dengan Integer.MAX_VALUE secara lalai.

PriorityBlockingQueue<E> ialah pembalut berbilang benang di atas PriorityQueue . Pembanding bertanggungjawab untuk logik yang mana elemen akan ditambah. Elemen terkecil keluar dahulu.

SynchronousQueue<E> - baris gilir berfungsi mengikut prinsip FIFO (first-in-first-out). Setiap operasi sisipan menyekat utas "Pengeluar" sehingga utas "Pengguna" menarik elemen daripada baris gilir dan begitu juga sebaliknya, "Pengguna" akan menunggu sehingga "Pengeluar" memasukkan elemen.

BlockingDeque<E> ialah antara muka yang menerangkan kaedah tambahan untuk baris gilir sekatan dua arah. Data boleh dimasukkan dan ditarik keluar dari kedua-dua belah baris gilir.

LinkedBlockingDeque<E> ialah baris gilir sekatan dwiarah pada nod terpaut, dilaksanakan sebagai senarai dwiarah mudah dengan satu kunci. Saiz baris gilir ditetapkan melalui pembina dan bersamaan dengan Integer.MAX_VALUE secara lalai.

TransferQueue<E> - antara muka menarik kerana apabila elemen ditambahkan pada baris gilir, adalah mungkin untuk menyekat benang Producer yang memasukkan sehingga benang Pengguna lain menarik elemen dari baris gilir. Anda juga boleh menambah cek untuk tamat masa tertentu atau menetapkan cek untuk Pengguna yang belum selesai . Hasilnya, kami mendapat mekanisme pemindahan data dengan sokongan untuk mesej tak segerak dan segerak.

LinkedTransferQueue<E> ialah pelaksanaan TransferQueue berdasarkan algoritma Dwi Baris dengan Slack. Banyak menggunakan CAS (lihat di atas) dan tempat letak benang apabila melahu.