Java ArrayDeque: คิวงานสองด้านโดยไม่ต้องใช้ LinkedList
ระบบงานเล็ก ๆ ที่ต้องหยิบงานเก่าสุดก่อน มักเริ่มจาก List.remove(0) ซึ่งต้องขยับสมาชิกที่เหลือทุกครั้งครับ ArrayDeque เป็น deque หรือคิวที่เพิ่มและหยิบได้ทั้งหัวและท้าย จึงใช้เป็น FIFO queue หรือ LIFO stack ได้ในคลาสเดียว เหมือนสายพานที่กำหนดได้ว่าจะรับและจ่ายกล่องทางไหน
เอกสาร Oracle ระบุว่าเป็น resizable array, โตตามต้องการ, ไม่รับ null และไม่ thread-safe หากหลาย thread แตะพร้อมกันต้องมี synchronization ภายนอก อย่าเปลี่ยนคิวที่หลาย worker ใช้มาเป็นคลาสนี้โดยตรง ตัวอย่างนี้ตั้งชื่อลงท้ายให้ชัดว่าเพิ่มท้ายและหยิบหัว แล้วทดสอบลำดับจริงด้วย assertions
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static void main(String[] args) {
Deque<String> jobs = new ArrayDeque<>();
jobs.addLast("parse");
jobs.addLast("validate");
jobs.addLast("publish");
assert jobs.removeFirst().equals("parse");
assert jobs.removeFirst().equals("validate");
assert jobs.removeFirst().equals("publish");
assert jobs.isEmpty();
Deque<Integer> history = new ArrayDeque<>();
history.addFirst(1);
history.addFirst(2);
assert history.removeFirst() == 2;
assert history.removeFirst() == 1;
boolean rejectedNull = false;
try { jobs.addLast(null); }
catch (NullPointerException expected) { rejectedNull = true; }
assert rejectedNull;
System.out.println("ArrayDeque tests passed");
}
}
เลือก method ให้โค้ดอ่านออก
addLast กับ removeFirst บอกทิศชัดกว่า push หรือ pop ในงาน queue; ถ้าเป็น stack ใช้ addFirst/removeFirst หรือ push/pop อย่างสม่ำเสมอ เมื่อคิวอาจว่าง เลือก pollFirst() เพื่อรับ null หรือ removeFirst() เพื่อให้ exception บอกว่า assumption พัง แต่เพราะสมาชิกจริงห้ามเป็น null การใช้ null เป็นผลของคิวว่างจึงไม่กำกวม
อย่าใช้ iterator เป็น snapshot: เอกสารอธิบายว่า iterator มัก fail-fast เมื่อคิวเปลี่ยน แต่ไม่มีสัญญาว่าจะตรวจทุก race ได้ ถ้าต้องแชร์งานข้าม thread ใช้ queue แบบ concurrent ที่ออกแบบมาสำหรับกรณีนั้น และเลือกนโยบาย backpressure ก่อนย้ายงานขึ้น production
Recap
- FIFO ใช้
addLastคู่removeFirstหรือpollFirst - LIFO ใช้หัวด้านเดียวกันทั้งเพิ่มและหยิบ
- ไม่ใส่
nullและไม่แชร์ArrayDequeข้าม thread โดยไม่มีการคุม - เทสต์ลำดับรับงานรวมถึงคิวว่าง