99 Ngày Java — Ngày 67: Concurrent collections
Một HashMap dùng chung không tự an toàn khi nhiều luồng ghi. Java cung cấp collection dành cho đồng thời, nhưng mỗi loại tối ưu một kiểu truy cập khác nhau. Chọn đúng cấu trúc thường đơn giản hơn tự khóa mọi thao tác; vẫn phải hiểu phạm vi nguyên tử và giới hạn bộ nhớ.

1. ConcurrentHashMap và thao tác nguyên tử
ConcurrentHashMap cho nhiều luồng đọc/ghi mà không khóa toàn bộ map. Tránh chuỗi containsKey rồi put: giữa hai bước, luồng khác có thể sửa dữ liệu. Dùng putIfAbsent, computeIfAbsent hoặc merge cho một khóa. Hàm mapping nên ngắn, không sửa chính map đó và không phụ thuộc hiệu ứng phụ.
ConcurrentHashMap<String, LongAdder> counts =
new ConcurrentHashMap<>();
counts.computeIfAbsent("ok", k -> new LongAdder())
.increment();2. CopyOnWriteArrayList cho đọc nhiều
Mỗi lần thay đổi tạo bản sao mảng bên dưới; iterator thấy snapshot tại thời điểm bắt đầu và không phản ánh thay đổi mới. Hợp với danh sách listener nhỏ, đọc rất nhiều và sửa hiếm. Với danh sách lớn hoặc ghi liên tục, chi phí sao chép và cấp phát sẽ cao.
CopyOnWriteArrayList<Listener> listeners =
new CopyOnWriteArrayList<>();
listeners.add(listener);
for (Listener each : listeners) each.onEvent(event);3. BlockingQueue và backpressure
BlockingQueue nối producer với consumer; put chờ khi queue đầy, take chờ khi rỗng. Chọn ArrayBlockingQueue có capacity hữu hạn để tải tăng không ăn hết bộ nhớ. Không tạo một worker cho mỗi item. Khi dừng, dùng interrupt hoặc một tín hiệu kết thúc có thiết kế; luôn quyết định xử lý item còn trong queue.
BlockingQueue<Job> jobs = new ArrayBlockingQueue<>(100);
jobs.put(job); // waits if full
Job next = jobs.take(); // waits if empty4. An toàn của collection không phủ cả workflow
Một lệnh của ConcurrentHashMap an toàn không có nghĩa hai lệnh liên tiếp là một giao dịch. Ví dụ chuyển điểm giữa hai key cần một bất biến chung; hãy dùng khóa nghiệp vụ, database transaction hoặc thiết kế lại dữ liệu. Đo contention và throughput thực tế trước khi đổi cấu trúc.
Map: cập nhật từng key; copy-on-write: đọc nhiều, sửa ít; queue: nối producer và consumer.
Bài tập: giới hạn queue rồi đo thời gian producer phải chờ khi consumer chậm.
Concurrent collection giúp giảm khóa thủ công, nhưng không thay thế thiết kế bất biến xuyên nhiều thao tác. Ngày 68 ta xem virtual threads để xử lý nhiều công việc chờ I/O.
Tài liệu đối chiếu
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/ConcurrentHashMap.html
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/CopyOnWriteArrayList.html
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/BlockingQueue.html
Site Admin
Engineer and writer. Building things with TypeScript and distributed systems.
Bình luận (0)
Bạn cần đăng nhập bằng Google để bình luận.
Hãy là người bình luận đầu tiên.


