Mô hình bộ nhớ luồng Java (JMM)

Hệ thống bộ nhớ cache máy tính

Vấn đề cần giải quyết
Bộ 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ồng

Ví 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ớ

Thẻ: Java Memory Model Concurrency

Đăng vào ngày 16 tháng 8 lúc 12:37