Hệ thống bộ nhớ cache máy tính
Vấn đề cần giải quyếtBộ nhớ cache CPU giúp giảm thời gian trung bình truy cập RAM. Vị trí thứ hai trong hệ thống lưu trữ phân cấp, chỉ sau thanh ghi CPU. Dung lượng nhỏ hơn RAM nhưng tốc độ trao đổi nhanh hơn nhiều. Quy trình hoạt động
Khi CPU yêu cầu truy cập bộ nhớ, sẽ kiểm tra trước trong cache. Nếu tồn tại (hit) thì trả về dữ liệu ngay. Nếu không tồn tại (miss) thì phải tải dữ liệu từ RAM vào cache trước khi trả về. Nguyên lý hoạt động
Hiệu quả của cache dựa trên tính địa phương (Locality) của chương trình. Bao gồm cả địa phương không gian (Spatial Locality) và địa phương thời gian (Temporal Locality).
Mô hình bộ nhớ luồng Java
Mô hình này tương tự hệ thống cache vật lý, được chuẩn hóa để che giấu khác biệt phần cứng. Luồng trực tiếp giao tiếp với bộ nhớ làm việc, và các biến chia sẻ sẽ được sao chép từ bộ nhớ chính vào bộ nhớ làm việc khi khởi tạo.Các thao tác nguyên tử phổ biến
lock: Đánh dấu biến ở trạng thái độc quyền trong bộ nhớ chính<br> read/load: Truyền giá trị từ bộ nhớ chính sang bộ nhớ làm việc<br> use/assign: Truyền giá trị đến engine thực thi và gán lại<br> store/write: Gửi giá trị từ bộ nhớ làm việc ra bộ nhớ chính<br> unlock: Giải phóng biến khỏi trạng thái khóa
Cơ chế volatile trong JMM
Sử dụng lệnh lock ở cấp độ assembly để đảm bảo tính nhất quán. Lệnh lock: - Ghi ngay dữ liệu cache vào RAM - Làm vô hiệu hóa cache trên các CPU khác - Khác biệt với khóa truyền thống là không cần chuyển ngữ cảnh luồngVí dụ minh họa volatile
class DauThi {
volatile boolean hoatDong = true;
void test() throws Exception {
Thread t1 = new Thread(() -> {
while(hoatDong) {}
System.out.println("Hoạt động kết thúc");
});
Thread t2 = new Thread(() -> {
Thread.sleep(2000);
hoatDong = false;
});
t1.start();
t2.start();
}
}
Kiểm tra double-check
class KiemTraKhoiTao {
private static volatile ThietBi thietBi;
static ThietBi getThietBi() {
if(thietBi == null) {
synchronized(KiemTraKhoiTao.class) {
if(thietBi == null)
thietBi = new ThietBi();
}
}
return thietBi;
}
}
Tính chất của volatile
- Đảm bảo tính khả kiến: Luôn đọc được giá trị mới nhất từ RAM
- Không đảm bảo tính nguyên tử: Phép toán tăng/giảm vẫn có thể xung đột
- Ngăn chặn sắp xếp lại lệnh nhờ barrier bộ nhớ