Họ đang đo gì
Bạn có biết đây là bài toán có cấu trúc chứ không phải xui rủi không.
Trả lời ngắn~30 giây
Bốn điều kiện Coffman: loại trừ lẫn nhau, giữ-và-chờ, không thu hồi được, và chờ vòng tròn. Trong thực tế mình phá cái cuối: luôn lấy khoá theo một THỨ TỰ TOÀN CỤC cố định — ví dụ sắp xếp id tăng dần trước khi khoá. Nó gần như miễn phí, không cần cơ chế phát hiện, và nó biến deadlock từ một sự cố ngẫu nhiên thành một điều không thể xảy ra.
Giải thích sâu
Ví dụ kinh điển là chuyển khoản: transfer(A, B) khoá A rồi B, trong khi transfer(B, A) chạy song song khoá B rồi A — và cả hai đứng lại vĩnh viễn. Sửa bằng cách khoá theo id nhỏ trước, bất kể chiều chuyển. Một dòng sort xoá bỏ hoàn toàn một loại sự cố, và nó là ví dụ dễ nhớ nhất để nói ra trong phỏng vấn.
Phá giữ-và-chờ là lựa chọn thứ hai: lấy TẤT CẢ khoá cần thiết một lần, thất bại thì nhả hết rồi thử lại. Nó tránh được deadlock nhưng mở ra livelock — hai bên liên tục nhả và thử lại đúng nhịp nhau — nên cần thêm backoff ngẫu nhiên. Đây là lý do thứ tự khoá thường được ưa hơn: nó không đổi một vấn đề lấy một vấn đề khác.
Trong database thì bạn không phá được điều kiện nào cả — engine tự phát hiện chu trình và huỷ một transaction. Nghĩa là ứng dụng BẮT BUỘC phải xử lý được lỗi deadlock bằng retry, và MySQL còn ghi lại chi tiết trong SHOW ENGINE INNODB STATUS để bạn tìm ra cặp câu lệnh gây ra nó.
// Deadlock: thứ tự khoá phụ thuộc vào tham số
void transfer(Account a, Account b, long amount) {
synchronized (a) { synchronized (b) { /* … */ } }
}
// An toàn: thứ tự khoá là toàn cục, không phụ thuộc lời gọi
void transfer(Account a, Account b, long amount) {
Account first = a.id() < b.id() ? a : b;
Account second = a.id() < b.id() ? b : a;
synchronized (first) { synchronized (second) { /* … */ } }
}Câu hỏi tiếp theo họ sẽ hỏi
?Livelock khác deadlock chỗ nào?
Deadlock thì các luồng đứng im; livelock thì chúng vẫn chạy, vẫn tốn CPU, mà không tiến triển — như hai người nhường đường liên tục sang cùng một bên. Khó phát hiện hơn vì mọi chỉ số đều trông như hệ thống đang bận làm việc.
Trả lời thế này là mất điểm
- Đề xuất timeout làm giải pháp chính. Nó biến treo vĩnh viễn thành lỗi định kỳ — tốt hơn, nhưng vẫn là chịu đựng chứ không phải sửa.
Nguồn
- Coffman, Elphick, Shoshani — System Deadlocks (1971), bốn điều kiện
- MySQL — InnoDB Deadlocks: phát hiện và cách đọc log