Java: Lỗi nhất quán bộ nhớ
Lỗi nhất quán bộ nhớ xảy ra khi các luồng khác nhau có các view không giống nhau lên cùng một dữ liệu. Nguyên nhân của lỗi nhất quán bộ nhớ rất phức tạp và vượt ra ngoài phạm vi của bài viết này. May mắn thay, lập trình viên không cần có hiểu biết sâu về các nguyên nhân này. Tất cả những gì cần thiết là một chiến lược để tránh loại lỗi này.
Chìa khóa để tránh lỗi nhất quán bộ nhớ là phải hiểu được mối quan hệ happens-before. Mối quan hệ này chỉ đơn giản là một sự đảm bảo rằng bộ nhớ được ghi bằng một câu lệnh cụ thể này có thể xuất hiện ở một câu lệnh cụ thể khác. Để rõ hơn điều này, ta hãy xét ví dụ sau. Giả sử có một biến kiểu int được định nghĩa và khởi tạo:
int counter = 0;
Biến count được chia sẻ giữa hai luồng A và B. Giả sử rằng luồng A tăng giá trị của counter:
counter++;
Rồi ngay sau đó luồng B in ra giá trị của counter:
System.out.println(counter);
Nếu hai câu lệnh trên được thực hiện trong cùng một luồng thì có thể giá trị in ra sẽ là "1". Nhưng nếu hai câu lệnh được thực hiện ở hai luồng riêng biệt thì giá trị in ra có thể là "0", từ "có thể" được dùng đến là bởi vì không có gì đảm bảo rằng luồng A thay đổi counter sẽ ảnh hưởng tới luồng A - trừ khi lập trình viên đã thiết lập một mối quan hệ happens-before giữa những câu lệnh này.
Ta có thể có một số cách để tạo quan hệ happens-before, một trong số đó là đồng bộ, như chúng ta sẽ thấy trong bài viết sau. Ở đây ta sẽ đề cập đến hai cách để có thể tạo quan hệ happens-before như sau:
-
Khi một câu lệnh gọi
Thread.start
thì mỗi một câu lệnh mà có quan hệ happens-before với câu lệnh cũng có quan hệ này với tất cả các câu lệnh đã được thực thi bởi một luồng mới. Các tác dụng của mã lệnh đó dẫn đến việc tạo ra luồng mới có thể xuất hiện ở luồng mới khác. -
Khi một luồng kết thúc và gây ra một
Thread.join
trong luồng khác để trở về thì tất cả các câu lệnh được thực hiện bởi luồng đã kết thúc mà quan hệ happens-before với tất cả các câu lệnh sau đó kết nối thành công.. Những ảnh hưởng của mã lệnh trong luồng hiện thời sẽ có thể xuất hiện ở luồng đã tham gia kết nối.