Trong Java, có hai cách chính để khóa tài nguyên chia sẻ giữa nhiều thread: sử dụng ReentrantLock (từ gói java.util.concurrent.locks kể từ Java 5) hoặc từ khóa synchronized.
ReentrantLock triển khai interface Lock và cung cấp các hoạt động mở rộng hơn so với synchronized theo tài liệu Java.
Bảng so sánh chi tiết
| STT | Tiêu chí | ReentrantLock | Synchronized |
|---|---|---|---|
| 1 | Cách lấy khóa | Gọi phương thức lock() |
Chỉ cần từ khóa synchronized |
| 2 | Cách giải phóng khóa | Gọi rõ ràng unlock() (thường trong khối finally) |
Tự động giải phóng khi thoát khối synchronized |
| 3 | Khả năng ngắt quãng (interrupt) | Hỗ trợ lockInterruptibly() để ngắt thread đang chờ |
Không có cách nào ngắt thread đang chờ khóa |
| 4 | Công bằng (Fairness) | Constructor có tham số fairness: true ưu tiên thread chờ lâu nhất |
Không đảm bảo thứ tự truy cập cụ thể |
| 5 | Thứ tự giải phóng khóa | Có thể giải phóng theo bất kỳ thứ tự nào | Phải giải phóng theo đúng thứ tự đã lấy (LIFO) |
Ví dụ ReentrantLock
public class ReentrantLockExample implements Runnable {
private Lock lock = new ReentrantLock();
@Override
public void run() {
try {
lock.lock();
// Thao tác với tài nguyên chia sẻ
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock(); // Luôn unlock trong finally
}
}
}
Ví dụ Synchronized
public class SynchronizedLockExample implements Runnable {
@Override
public void run() {
synchronized (resource) {
// Thao tác với tài nguyên chia sẻ
} // Tự động unlock khi thoát khối
}
}
Khi nào dùng cái nào?
- Synchronized: Đơn giản, phù hợp cho các trường hợp cơ bản, ít cạnh tranh.
- ReentrantLock: Cần tính năng nâng cao: timeout, interruptible, fairness, condition variables, hoặc khóa không theo block structure.