คิวที่ไม่ปิดกั้น

การใช้งานคิวที่ปลอดภัยสำหรับ เธรดและที่สำคัญที่สุดคือไม่บล็อกบนโหนดที่เชื่อมโยง

ConcurrentLinkedQueue<E> - ใช้อัลกอริทึมแบบไม่ต้องรอที่ปรับให้ทำงานร่วมกับตัวรวบรวมขยะ อัลกอริทึมนี้ค่อนข้างมีประสิทธิภาพและรวดเร็วมาก เนื่องจากสร้างขึ้นจาก CAS เมธอด size()สามารถรันได้เป็นเวลานาน ดังนั้นจึงไม่ควรดึงเมธอดตลอดเวลา

ConcurrentLinkedDeque<E> - Deque หมายถึงคิวสิ้นสุดสองครั้ง ซึ่งหมายความว่าสามารถเพิ่มและดึงข้อมูลจากทั้งสองด้านได้ ดังนั้น คลาสจึงรองรับการทำงานทั้งสองโหมด: FIFO (เข้าก่อนออกก่อน) และ LIFO (เข้าก่อนออกก่อน)

ในทางปฏิบัติ ควรใช้ ConcurrentLinkedDequeถ้า LIFO มีความจำเป็นจริงๆ เนื่องจากโหนดเป็นแบบสองทิศทาง คลาสนี้จึงสูญเสียประสิทธิภาพไปครึ่งหนึ่งเมื่อเทียบกับ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();
           }
       }
   }
}

การบล็อกคิว

อินเทอร์เฟซBlockingQueue<E> - หากมีข้อมูลจำนวนมาก แสดงว่าConcurrentLinkedQueueไม่เพียงพอ

เมื่อเธรดล้มเหลวในการทำงาน คุณสามารถรับOutOfMemmoryException ได้อย่าง ง่ายดาย และเพื่อไม่ให้กรณีดังกล่าวเกิดขึ้น เรามีBlockingQueue สำหรับการทำงาน กับวิธีการต่างๆ ในการเติมและทำงานกับคิวและการล็อกแบบมีเงื่อนไข

BlockingQueueไม่รู้จักองค์ประกอบ null และพ่น NullPointerExceptionเมื่อพยายามเพิ่มหรือรับองค์ประกอบดังกล่าว วิธีการสำรวจจะส่งคืนองค์ประกอบ null หากไม่มีการวางองค์ประกอบในคิวภายในระยะหมดเวลา

BlockingQueue<E> การใช้งาน

มาดู การใช้งาน BlockingQueue ของเราอย่างละเอียดยิ่งขึ้น :

ArrayBlockingQueue<E>เป็นคลาสคิวการบล็อกที่สร้างขึ้นบนบัฟเฟอร์วงแหวนแบบคลาสสิก ที่นี่เรามีโอกาสที่จะจัดการ "ความซื่อสัตย์" ของล็อค หากยุติธรรม=เท็จ (ค่าเริ่มต้น) ลำดับของเธรดจะไม่รับประกัน

DelayQueue<E ขยาย Delayed>เป็นคลาสที่อนุญาตให้คุณดึงองค์ประกอบจากคิวหลังจากการหน่วงเวลาที่กำหนดเท่านั้น ซึ่งกำหนดไว้ในแต่ละองค์ประกอบผ่านเมธอดgetDelayของอินเทอร์เฟซ Delayed

LinkedBlockingQueue<E>เป็นคิวบล็อกบนโหนดที่เชื่อมโยง ซึ่งใช้งานบนอัลกอริทึม “คิวล็อคสองคิว”: ล็อคแรกใช้สำหรับเพิ่ม ส่วนที่สองใช้สำหรับดึงองค์ประกอบจากคิว เนื่องจากการล็อก เมื่อเทียบกับ ArrayBlockingQueueคลาสนี้จึงมีประสิทธิภาพสูง แต่ต้องใช้หน่วยความจำมากกว่า ขนาดคิวถูกตั้งค่าผ่านตัวสร้างและเท่ากับ Integer.MAX_VALUE โดยค่าเริ่มต้น

PriorityBlockingQueue<E>เป็น wrapper แบบหลายเธรดเหนือ PriorityQueue ตัวเปรียบเทียบมีหน้าที่รับผิดชอบตรรกะที่องค์ประกอบจะถูกเพิ่มเข้าไป องค์ประกอบที่เล็กที่สุดจะออกมาก่อน

SynchronousQueue<E> - คิวทำงานตามหลักการ FIFO (เข้าก่อนออกก่อน) การดำเนินการแทรกแต่ละครั้งจะบล็อกเธรด "ผู้ผลิต" จนกว่าเธรด "ผู้บริโภค" จะดึงองค์ประกอบออกจากคิว และในทางกลับกัน "ผู้บริโภค" จะรอจนกว่า "ผู้ผลิต" จะแทรกองค์ประกอบ

BlockingDeque<E>เป็นอินเทอร์เฟซที่อธิบายวิธีการเพิ่มเติมสำหรับคิวการบล็อกแบบสองทิศทาง สามารถแทรกและดึงข้อมูลจากทั้งสองด้านของคิว

LinkedBlockingDeque<E>เป็นคิวบล็อกแบบสองทิศทางบนโหนดที่เชื่อมโยง ใช้งานเป็นรายการแบบสองทิศทางอย่างง่ายด้วยการล็อกเพียงครั้งเดียว ขนาดคิวถูกตั้งค่าผ่านตัวสร้างและเท่ากับ Integer.MAX_VALUE โดยค่าเริ่มต้น

TransferQueue<E> - อินเทอร์เฟซมีความน่าสนใจตรงที่เมื่อมีการเพิ่มองค์ประกอบลงในคิว เป็นไปได้ที่จะบล็อกการแทรกเธรด Producerจนกว่า เธรด Consumer อื่น จะดึงองค์ประกอบจากคิว คุณยังสามารถเพิ่มการตรวจสอบสำหรับการหมด เวลาที่กำหนด หรือตั้งค่าการตรวจสอบสำหรับผู้บริโภคที่รอดำเนินการ เป็นผลให้เราได้รับกลไกการถ่ายโอนข้อมูลพร้อมรองรับข้อความอะซิงโครนัสและซิงโครนัส

LinkedTransferQueue<E>เป็นการนำ TransferQueueไปใช้ตามอัลกอริทึม Dual Queues พร้อม Slack ใช้งานหนักของ CAS (ดูด้านบน) และการจอดเธรดเมื่อไม่ได้ใช้งาน