Đây là một ví dụ, bởi vì một ví dụ thường rõ ràng hơn một lời giải thích dài. Giả sử foo
là một biến của loại long
. Các hoạt động sau đây không phải là một hoạt động nguyên tử:
foo = 65465498L;
Thật vậy, biến được viết bằng hai thao tác riêng biệt: một thao tác ghi 32 bit đầu tiên và biến thứ hai ghi 32 bit cuối. Điều đó có nghĩa là một luồng khác có thể đọc giá trị của foo
và xem trạng thái trung gian.
Làm cho nguyên tử hoạt động bao gồm sử dụng các cơ chế đồng bộ hóa để đảm bảo rằng hoạt động được nhìn thấy, từ bất kỳ luồng nào khác, dưới dạng một nguyên tử đơn lẻ (nghĩa là không thể chia tách trong các bộ phận), hoạt động. Điều đó có nghĩa là bất kỳ luồng nào khác, một khi hoạt động được tạo thành nguyên tử, sẽ thấy giá trị của foo
trước khi gán hoặc sau khi gán. Nhưng không bao giờ là giá trị trung gian.
Một cách đơn giản để làm điều này là làm cho biến số biến động :
private volatile long foo;
Hoặc để đồng bộ hóa mọi quyền truy cập vào biến:
public synchronized void setFoo(long value) {
this.foo = value;
}
public synchronized long getFoo() {
return this.foo;
}
// no other use of foo outside of these two methods, unless also synchronized
Hoặc để thay thế nó bằng AtomicLong
:
private AtomicLong foo;