Java ConcurrentHashMap.newKeySet: ทำ concurrent set โดยไม่ใส่ Boolean หลอก
ถ้าหลาย thread ต้องตอบเพียงว่า “เคยเห็น id นี้หรือยัง” การใช้ ConcurrentHashMap<String, Boolean> ทำให้ value เป็นของหลอกครับ ConcurrentHashMap.newKeySet() คืน concurrent set ที่สื่อ contract ตรงกว่า และ add บอกได้ทันทีว่าเราเป็นคนเพิ่มรายแรกหรือไม่
WHY: ให้ชนิดข้อมูลบอกเจตนา
เหมือนจุดแจกบัตรคิวที่สนใจเพียงเลขบัตร ไม่ได้ต้องจด true หลังทุกหมายเลข Set ลดโอกาสที่คนจะตีความ value ผิด และทำให้โค้ด dedup อ่านเป็นประโยค if (seen.add(id)) { ... }
HOW: รับเหตุการณ์ซ้ำจากหลาย worker
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws Exception {
Set<String> seen = ConcurrentHashMap.newKeySet();
ExecutorService pool = Executors.newFixedThreadPool(4);
try {
for (int i = 0; i < 100; i++) {
int id = i % 10;
pool.submit(() -> seen.add("job-" + id));
}
} finally {
pool.shutdown();
assert pool.awaitTermination(2, TimeUnit.SECONDS);
}
assert seen.size() == 10 : seen;
assert !seen.add("job-3") : "duplicate must return false";
assert seen.add("job-10") : "new key must return true";
}
}
Set นี้ไม่รับ null ตาม contract ของ ConcurrentHashMap และ iterator เป็น weakly consistent: มองเห็นสถานะบางช่วงระหว่างการเปลี่ยนแปลงได้โดยไม่โยน ConcurrentModificationException จึงอย่าใช้การวนรายการเป็น snapshot ทางบัญชี
ขอบเขตที่ต้องเลือก map แทน
ถ้าต้องเก็บ timestamp, retry count หรือ owner ต่อ key ให้ใช้ ConcurrentHashMap<K,V> จริง และอัปเดตด้วย compute/merge ตาม semantics งาน newKeySet เหมาะกับ membership เท่านั้น นอกจากนี้ dedup ในหน่วยความจำไม่ durable; process restart แล้วลืมทั้งหมด ถ้างานห้ามทำซ้ำข้าม restart ต้องมีฐานข้อมูลหรือ idempotency key ที่ชั้นปลายทาง
Recap
- ใช้
newKeySetเมื่อต้องการ membership concurrent อย่างเดียว - ใช้ค่าคืนจาก
addเพื่อรู้ว่าเป็นผู้เพิ่มรายแรก - อย่าถือ iterator เป็น snapshot แบบหยุดเวลา
- เพิ่ม durable idempotency เมื่อ restart แล้วห้ามทำซ้ำ