99 Ngày Java — Ngày 70: Tổng kết concurrency: chọn đúng công cụ
Từ ngày 61 đến 69, ta đã đi từ thread cơ bản tới future, lock, concurrent collection và virtual thread. Vấn đề khó nhất không phải cú pháp mà là chọn đúng công cụ và xác định điều gì phải đúng khi nhiều việc xảy ra cùng lúc. Hãy bắt đầu từ bất biến dữ liệu, nguồn tải và cách thất bại.

1. Race condition và visibility
Một phép count++ không nguyên tử. volatile bảo đảm visibility cho biến, không biến chuỗi đọc–tăng–ghi thành nguyên tử. Chọn AtomicInteger/LongAdder cho bộ đếm, lock cho bất biến nhiều field, immutable value khi không cần sửa. Viết test nhiều luồng với điểm bắt đầu đồng bộ và lặp lại để tăng khả năng thấy lỗi.
AtomicInteger count = new AtomicInteger();
count.incrementAndGet(); // atomic per counter
// Multi-field invariants need a broader boundary.2. Chọn công cụ theo luồng công việc
ExecutorService quản lý task; CompletableFuture ghép kết quả phụ thuộc/độc lập; BlockingQueue có capacity nối producer–consumer; ConcurrentHashMap cập nhật theo key; ReentrantLock bảo vệ vùng quan trọng. Virtual thread hợp với nhiều task chờ I/O, nhưng vẫn phải giới hạn kết nối và request đang chạy. Không dùng nhiều công cụ chỉ vì chúng có sẵn.
// Need a result? Future / CompletableFuture.
// Need handoff and backpressure? BlockingQueue.
// Need one shared invariant? Lock or transaction.3. Hủy, timeout và đóng tài nguyên
Timeout của Future không bảo đảm I/O bên dưới đã dừng. Task nên xử lý interrupt và đóng kết nối theo hợp đồng thư viện. Luôn đặt unlock trong finally, đóng executor đúng vòng đời và remove ThreadLocal ở pool. Tránh chờ future trong cùng pool nhỏ khi task được chờ cũng cần pool đó.
Future<?> task = pool.submit(this::work);
try { task.get(2, TimeUnit.SECONDS); }
catch (TimeoutException e) { task.cancel(true); }
// Ensure work responds to interruption.4. Checklist trước production
Xác định dữ liệu nào chia sẻ, ai sở hữu nó, và thao tác nào phải nguyên tử. Đặt giới hạn queue, pool, kết nối và deadline. Đo latency, throughput, số task đang chờ và lỗi; thử tải tăng đột ngột, lỗi đối tác và shutdown. Thread dump/JFR giúp điều tra deadlock, starvation và pinning thay vì đoán.
Đúng kết quả trước; giới hạn tài nguyên sau; đo hiệu năng trên tải đại diện.
Mỗi task cần đường thành công, lỗi, timeout, hủy và shutdown.
Concurrency tốt là dữ liệu đúng dưới tải và lỗi, với tài nguyên có giới hạn. Giữ checklist này khi sang các chủ đề tiếp theo. Ngày 71 chuyển sang bộ nhớ JVM: heap, stack và metaspace.
Tài liệu đối chiếu
https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/concurrent/package-summary.html
https://docs.oracle.com/en/java/javase/21/core/virtual-threads.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.


