Java - Happens Before Relationship
"Happens-before" là một khái niệm trong Java Memory Model (JMM) dùng để chỉ định mối quan hệ thứ tự giữa các thao tác (operations) trên bộ nhớ, đảm bảo rằng các thao tác xảy ra trước (happens-before) một thao tác khác sẽ được thực hiện và "nhìn thấy" bởi thao tác sau đó. Điều này giúp đảm bảo tính nhất quán và tránh các vấn đề liên quan đến tối ưu hoá của trình biên dịch hoặc bộ xử lý.
Một số điểm chính:
- Đảm bảo thứ tự: Nếu thao tác A happens-before thao tác B, thì tất cả các thay đổi của A sẽ được thấy bởi B.
- Ứng dụng trong đa luồng: Mối quan hệ happens-before được sử dụng để đảm bảo rằng dữ liệu được ghi bởi một thread sẽ được các thread khác nhìn thấy đúng cách.
- Các quy tắc happens-before:
- Trong cùng một thread, thứ tự chương trình (program order) đảm bảo rằng lệnh viết xảy ra trước lệnh đọc.
- Đối với các thao tác đồng bộ hoá: Khóa (lock) và giải khóa (unlock) cung cấp mối quan hệ happens-before.
- Biến được khai báo với
volatile: Ghi vào biến volatile happens-before bất kỳ đọc nào sau đó của biến volatile đó. - Giao tiếp qua các thread khởi tạo và kết thúc: Thread chính (main thread) happens-before các thread con được khởi tạo và ngược lại, khi thread con kết thúc, thì các thao tác trong thread con happens-before thao tác join() trên thread đó.
Ví dụ minh họa với volatile:
public class HappensBeforeExample {
private volatile boolean flag = false;
private int data = 0;
// Thread A: thực hiện ghi dữ liệu
public void writer() {
data = 42; // Thao tác ghi dữ liệu
flag = true; // Thao tác ghi volatile
}
// Thread B: đọc dữ liệu
public void reader() {
if (flag) { // Đọc volatile, đảm bảo happens-before
System.out.println("Data = " + data); // Đảm bảo đọc được giá trị 42
}
}
}
Giải thích ví dụ:
- Trong thread writer(), khi
data = 42được thực hiện trướcflag = true, và vìflaglà biến volatile, nên thao tác ghiflag = truesẽ tạo ra mối quan hệ happens-before với bất kỳ thao tác đọc volatileflagsau đó. - Trong thread reader(), khi đọc
flagvà phát hiện giá trị làtrue, mối quan hệ happens-before đảm bảo rằng tất cả các thao tác ghi trước đó trong thread writer (nhưdata = 42) cũng sẽ được thấy trong thread reader. Như vậy, khi in radata, giá trị 42 được đảm bảo.
Tóm lại, happens-before là một nguyên tắc quan trọng trong việc quản lý thứ tự và tính nhất quán của các thao tác trên bộ nhớ trong lập trình đa luồng. Nó giúp các lập trình viên đảm bảo rằng dữ liệu được chia sẻ giữa các thread sẽ luôn được cập nhật đúng cách, tránh những lỗi liên quan đến bộ nhớ cache và tối ưu hoá của hệ thống.