Learning Outcome & Exercises: Concurrency
Tổng kết chương Concurrency: học xong mình phải làm được gì, và làm bài tập nào để chứng minh?
Đọc hiểu chưa đủ để đi phỏng vấn. Mỗi chương kết thúc bằng những việc làm được và chứng minh được: có code chạy, có test cho cả trường hợp lỗi, có log hoặc số đo. Bài tập nằm trong repo riêng java-backend-interview-labs, thư mục labs/concurrency.
1. Mục tiêu đầu ra
Học xong chương này, bạn tự làm được:
- Tái hiện lost update bằng test và chứng minh synchronized / ReentrantLock / AtomicLong / LongAdder cho kết quả đúng.
- Chứng minh synchronized không bảo vệ dữ liệu khi có hai instance, và atomic UPDATE ở database thì có.
- Đo được khác biệt giữa pool platform thread và virtual thread với tác vụ I/O, và vẫn giới hạn downstream bằng Semaphore.
- Phân biệt async (CompletableFuture) với non-blocking I/O bằng log tên thread.
2. Basic: Tái hiện race condition
Trạng thái: ✅ Đã có code + test pass (2026-10-15)
1000 thread × 100 lần increment trên 5 kiểu counter; bản value++ phải mất update, 4 bản còn lại đúng 100 000.
Bài liên quan: synchronized, volatile, atomic, ReentrantLock & ReadWriteLock
Hoàn thành khi:
- Test pass
- Log ghi số lần mất update của bản không đồng bộ
Bằng chứng: CounterRaceTest trong labs/concurrency (thư mục evidence/).
3. Intermediate: Lost update giữa hai instance
Trạng thái: ✅ Đã có code + test pass (2026-10-15)
Hai WalletService dùng chung database: read-modify-write + synchronized cho 1100 thay vì 1200; atomic UPDATE cho 1200; trừ tiền có điều kiện không bao giờ âm. Thêm fan-out 3 call bằng CompletableFuture có timeout.
Bài liên quan: Race condition: hai request cùng sửa một dữ liệu, ReentrantLock & ReadWriteLock, CompletableFuture
Hoàn thành khi:
- Có failure case lost update lặp lại được (CyclicBarrier)
- Timeout trả TimeoutException
- README giải thích vì sao synchronized không đủ
Bằng chứng: WalletMultiInstanceTest, CheckoutAggregatorTest trong labs/concurrency (thư mục evidence/).
4. Challenge: Virtual thread dưới tải I/O
Trạng thái: 🟡 Một phần đã có test, phần còn lại chưa làm
1000 tác vụ I/O: so sánh pool 20 thread với virtual thread; giới hạn 50 call bằng Semaphore. Phần còn lại: phát hiện pinning trên Java 21 bằng -Djdk.tracePinnedThreads hoặc JFR.
Bài liên quan: Virtual threads, Thread pool & ExecutorService
Hoàn thành khi:
- Số đo thời gian và maxInFlight trong evidence/
- TODO: log pinning khi gọi I/O trong synchronized
Bằng chứng: VirtualThreadIoTest trong labs/concurrency (thư mục evidence/).
5. Tiêu chí hoàn thành chung
- Tự giải thích được bài toán và vì sao chọn giải pháp.
- Code chạy được bằng lệnh ghi trong README, không chứa secret.
- Có test tự động cho happy path và failure path.
- Có log hoặc số đo trong
evidence/chứng minh kết quả. - Có câu trả lời phỏng vấn ngắn bằng tiếng Việt và tiếng Anh.
- README của lab có link ngược về bài học tương ứng.
6. Lab và trạng thái
| Mức | Bài tập | Trạng thái | Test / bằng chứng |
|---|---|---|---|
| Basic | Tái hiện race condition | ✅ Đã có code + test pass (2026-10-15) | CounterRaceTest |
| Intermediate | Lost update giữa hai instance | ✅ Đã có code + test pass (2026-10-15) | WalletMultiInstanceTest, CheckoutAggregatorTest |
| Challenge | Virtual thread dưới tải I/O | 🟡 Một phần đã có test, phần còn lại chưa làm | VirtualThreadIoTest |
Repo lab: java-backend-interview-labs/labs/concurrency. TODO: link GitHub là placeholder cho tới khi repo được push.
evidence/; chỉ đánh dấu xong khi có bằng chứng.Phỏng vấn hỏi về Concurrency, câu nào hay gặp nhất và trả lời sao?
Q1. Code đã có synchronized, deploy 2 instance thì có còn race condition không?
🇻🇳 Tiếng Việt:
Có. synchronized khóa monitor của object trong một JVM, hai instance có hai monitor riêng. Với dữ liệu dùng chung em đưa đồng bộ xuống database bằng atomic update, optimistic lock hoặc SELECT FOR UPDATE.
🇬🇧 English:
Yes. synchronized locks an object's monitor inside one JVM, and two instances have two separate monitors. For shared data I move coordination to the database with an atomic update, optimistic locking or SELECT FOR UPDATE.
Cách nhớ ngắn gọn
- Mỗi bài tập = code + test + log.
- Luôn có ít nhất một failure case.
- Chưa có bằng chứng thì chưa xong.
Tự kiểm tra
Bài tập Basic (Tái hiện race condition) được coi là xong khi nào?
Test pass; Log ghi số lần mất update của bản không đồng bộ. Chưa có code chạy và bằng chứng thì chưa tính là xong.
Bài tập Intermediate (Lost update giữa hai instance) được coi là xong khi nào?
Có failure case lost update lặp lại được (CyclicBarrier); Timeout trả TimeoutException; README giải thích vì sao synchronized không đủ. Chưa có code chạy và bằng chứng thì chưa tính là xong.
Bài tập Challenge (Virtual thread dưới tải I/O) được coi là xong khi nào?
Số đo thời gian và maxInFlight trong evidence/; TODO: log pinning khi gọi I/O trong synchronized. Chưa có code chạy và bằng chứng thì chưa tính là xong.