Java Internals & Concurrency/Module 01 — Concurrency cơ bản: tổng quan
1/39
Bài 1 / 39~10 phútConcurrency cơ bảnMiễn phí lượt xem

Module 01 — Concurrency cơ bản: tổng quan

Bản đồ 17 bài của module concurrency: từ process/thread và race condition, qua bộ công cụ đồng bộ của java.util.concurrent, tới kiến trúc executor, virtual thread và structured concurrency — tất cả xoay quanh capstone TicketFlow.

TL;DR: Module này dạy cách viết code Java đúng khi nhiều thread cùng chạm vào dữ liệu. 17 bài chia ba phần: nền tảng (vì sao race condition xảy ra và bốn chiến lược thread safety), công cụ (atomic, lock, concurrent collection, blocking queue, synchronizer), và kiến trúc (executor, CompletableFuture, fork/join, virtual thread, structured concurrency). Một capstone duy nhất — hệ thống đặt vé TicketFlow — tiến hóa từ v0 đầy race condition tới v4 chạy trên virtual thread, để mỗi công cụ mới đều được gắn vào đúng một vấn đề thật.

Vì sao module này tồn tại

Hãy hình dung một tình huống mà gần như mọi team backend đều từng gặp một biến thể của nó. TicketFlow — hệ thống đặt vé sự kiện — mở bán 500 vé cho một đêm nhạc. Code đặt vé rất hợp lý: đọc số vé đã bán, kiểm tra còn chỗ, ghi tăng một. Test pass, staging chạy mượt. Đêm mở bán, 2.000 người bấm nút cùng lúc — và sáng hôm sau, database ghi nhận 503 vé đã bán cho 500 ghế. Ba khách hàng cầm vé hợp lệ cho ghế không tồn tại.

Không một dòng nào trong code đó sai khi chạy đơn luồng. Nó chỉ sai khi hai thread cùng đọc thấy "còn một chỗ" rồi cùng bán. Loại bug này không xuất hiện trong unit test, không tái hiện được trên máy dev, chỉ bùng ra dưới tải thật — và khi đã ra production thì chi phí không đo bằng giờ debug mà bằng tiền hoàn vé và niềm tin của khách.

Concurrency là kỹ năng phân tầng dev Java rõ nhất: ai cũng viết được code chạy được trên nhiều thread, nhưng viết code chạy đúng đòi hỏi hiểu cơ chế — memory model, happens-before, compound action, contention. Module này xây từng viên gạch của phần hiểu đó, và dùng chính bug oversell ở trên làm sợi chỉ xuyên suốt: bạn sẽ gặp lại nó ở bài thread safety dưới tên BookingService v0, rồi tự tay vá nó bằng từng công cụ học được.

Sau module này bạn sẽ

  • Giải thích được vì sao concurrency bug xảy ra: shared mutable state, hai vấn đề độc lập atomicity và visibility, và quan hệ happens-before của Java Memory Model.
  • Chẩn đoán được race condition trong code thật bằng cách trace các interleaving xui xẻo nhất và chỉ ra compound action không nguyên tử.
  • Triển khai được class thread-safe theo bốn chiến lược: confinement, immutability, synchronization, và delegation cho concurrent collection.
  • Chọn đúng cơ chế đồng bộ — volatile, synchronized, Atomic/LongAdder, ReentrantLock, ReadWriteLock/StampedLock hay ConcurrentHashMap — theo pattern truy cập và mức contention.
  • Thiết kế được kiến trúc thực thi tách task khỏi thread: producer–consumer với BlockingQueue, thread pool tuning có backpressure, và pipeline async bằng CompletableFuture.
  • Trace được vòng đời một request trên virtual thread — mount/unmount, pinning — và quyết định khi nào di cư từ thread pool sang virtual thread cùng structured concurrency.

Lộ trình module

Mười bảy bài xếp thành ba phần, và thứ tự của chúng không ngẫu nhiên.

Phần 1 — Nền tảng (bài 01–06): trước khi cầm bất kỳ công cụ nào, bạn cần hiểu vấn đề. Bài 01–02 dựng khung từ hệ điều hành lên: process, thread, vòng đời và cách hủy một thread tử tế. Bài 03 đặt viên đá trung tâm của cả module — shared mutable state — và mổ xẻ hai loại lỗi độc lập: atomicity và visibility. Đây cũng là nơi TicketFlow v0 xuất hiện với đúng bug oversell ở trên. Bài 04–05 dạy hai cách vấn đề: không chia sẻ (confinement) và không thay đổi (immutability). Chỉ khi cả hai đường né đều không đi được, bài 06 mới rút công cụ đồng bộ đầu tiên: volatilesynchronized — TicketFlow lên v1, vá race bằng Monitor Pattern.

Phần 2 — Công cụ (bài 07–12): synchronized đúng nhưng thô. Phần này mở dần hộp đồ nghề của java.util.concurrent theo trục từ thấp lên cao: CAS và Atomic (07) cho thao tác một biến không cần khóa; explicit lock (08) rồi ReadWriteLock, StampedLock và AQS (09) khi cần khả năng mà synchronized không có; delegation cho ConcurrentHashMap (10) — TicketFlow lên v2 với compute nguyên tử per-key; BlockingQueue và producer–consumer (11); rồi các synchronizer điều phối tiến độ (12).

Phần 3 — Kiến trúc (bài 13–17): khi công cụ đã đủ, câu hỏi đổi từ "khóa thế nào" sang "tổ chức thực thi thế nào". Executor và thread pool (13) tách task khỏi thread; CompletableFuture (14) ghép task thành pipeline async — TicketFlow v3; fork/join (15) cho divide-and-conquer thuần CPU; virtual thread (16) phá cái trần kích thước pool — TicketFlow v4; và structured concurrency cùng ScopedValue (17) khép series bằng kỷ luật vòng đời cho thế giới hậu Loom.

flowchart LR
    subgraph P1["Phan 1 - Nen tang (01-06)"]
        A["Thread va<br/>race condition"] --> B["4 chien luoc<br/>thread safety"]
    end
    subgraph P2["Phan 2 - Cong cu (07-12)"]
        C["Atomic / Lock /<br/>CHM / Queue"]
    end
    subgraph P3["Phan 3 - Kien truc (13-17)"]
        D["Executor /<br/>CompletableFuture"] --> E["Virtual thread /<br/>Structured concurrency"]
    end
    B --> C --> D
    P1 -.-> V0["TicketFlow v0 -> v1"]
    P2 -.-> V2["TicketFlow v2"]
    P3 -.-> V4["TicketFlow v3 -> v4"]

Yêu cầu trước khi bắt đầu

  • Hoàn thành course Java Foundations — đặc biệt phần collections (HashMap, List) và exception, vì code ví dụ dùng chúng liên tục.
  • Hoàn thành course Java OO & Functional — record, lambda, Stream xuất hiện từ những bài đầu mà không giải thích lại.
  • JDK 25 (baseline của series — virtual thread, ScopedValue, StructuredTaskScope đều theo hành vi bản này) và một IDE chạy được JUnit để tự tái hiện race condition.

Time budget

BàiChủ đềPhút
01Process và thread~15
02Thread API và vòng đời~13
03Thread safety~12
04Confinement~10
05Immutability~8
06volatile & synchronized~12
07Atomic & CAS~10
08ReentrantLock và Condition~12
09ReadWriteLock, StampedLock và AQS~12
10Delegation & concurrent collections~10
11Blocking queue & producer–consumer~11
12Synchronizers~11
13Executor & thread pool~11
14Future & CompletableFuture~12
15Fork/Join~10
16Virtual threads~8
17Structured concurrency & ScopedValue~11

Tổng cộng khoảng 3 giờ 10 phút đọc (cộng tổng quan và tổng kết là ~3,5 giờ). Nếu bạn chạy lại các ví dụ race condition và tự sửa TicketFlow theo từng phiên bản — rất nên — hãy dự trù 5 tới 6 giờ cho cả module, chia thành nhiều phiên ngắn thay vì một lần ngồi.

Cách học module này hiệu quả

  1. Chạy code race nhiều lần, không phải một lần. Race condition phụ thuộc lập lịch: một lần chạy ra kết quả đúng không chứng minh code đúng. Chạy ví dụ lỗi 10–20 lần (hoặc bọc trong vòng lặp), quan sát kết quả dao động — cảm giác "lúc đúng lúc sai" chính là bài học.
  2. Vẽ timeline interleaving bằng tay. Với mỗi bug trong bài, lấy giấy kẻ hai cột Thread A / Thread B rồi xếp từng bước đọc–kiểm–ghi theo thứ tự xui xẻo nhất. Kỹ năng trace interleaving này là thứ phỏng vấn senior kiểm tra, và không học được bằng cách đọc suông.
  3. Theo sát TicketFlow qua từng phiên bản. Mỗi lần capstone lên version mới, dừng lại tự hỏi: phiên bản trước hỏng ở đâu, công cụ mới vá đúng chỗ nào, và trả giá gì. So sánh giữa các version đáng giá hơn ghi nhớ API.
  4. Đừng học thuộc API, học tiêu chí chọn. java.util.concurrent có hàng chục class; thứ đọng lại phải là bảng quyết định "tình huống nào → công cụ nào" (bài tổng kết có cheat sheet đúng cho việc này).
  5. Phần 1 chậm mà chắc. Bài 03 (thread safety) là móng của mọi bài sau — nếu atomicity vs visibility còn mơ hồ, các bài lock và atomic sẽ thành học vẹt. Đọc lại bài 03 lần thứ hai trước khi vào phần 2 là khoản đầu tư hời.

Bài đầu tiên: Process và Thread

Bài này có giúp bạn hiểu bản chất không?

Hỏi đáp về bài này

Chưa có câu hỏi

Đặt câu hỏi

Có gì chưa rõ trong bài? Đặt câu hỏi đầu tiên — câu trả lời từ cộng đồng giúp bạn (và người sau).

Đặt câu hỏi đầu tiên