Những phép toán nào trong Java được coi là nguyên tử?


Câu trả lời:


100
  • tất cả các phép gán của kiểu nguyên thủy ngoại trừ dài và kép
  • tất cả các bài tập của tài liệu tham khảo
  • tất cả các phép gán của các biến biến động
  • tất cả các hoạt động của các lớp java.concurrent.Atomic *

và có thể nhiều thứ khác. Nhìn vào jls .

Như đã lưu ý trong các nhận xét, tính nguyên tử không bao hàm khả năng hiển thị. Vì vậy, trong khi một luồng khác được đảm bảo không nhìn thấy một phần được viết int, nó có thể không bao giờ thấy giá trị mới.

Các hoạt động trên dài và gấp đôi cũng trên CPU nguyên tử 64 bit phổ biến , mặc dù không có gì đảm bảo. Xem thêm yêu cầu tính năng này .


21
Các bài tập về volatilelong và đôi được đảm bảo là nguyên tử: java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7
Joonas Pulakka

12
Ngoài ra, hãy nhớ rằng trong khi các hoạt động là nguyên tử, khả năng hiển thị của các hoạt động đó có thể không được đảm bảo trong một ứng dụng đa luồng trừ khi được cẩn thận đặc biệt (các chi tiết ở đây là cách phức tạp để mô tả trong một nhận xét ..)
nos

5
64 bit jvm, long and double assignments are also atomic.Bạn có chắc không? Tôi muốn nói rằng chúng dành cho mã đã biên dịch, nhưng mã được thông dịch thì sao? Có lẽ bạn đúng, nhưng có gì đảm bảo không?
maaartinus

4
Thông số kỹ thuật vẫn không bắt buộc các JVM 64 bit cung cấp tính nguyên tử cho các bài tập dài và gấp đôi. java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7 Nói một cách nổi tiếng, "hành vi này là triển khai cụ thể". Tuy nhiên, có nhiều khả năng hơn là không, các máy ảo 64-bit sẽ thực hiện nó như một hoạt động nguyên tử.
sjlee

1
IMHO, các phép gán tham chiếu thông thường là nguyên tử, nhưng AtomicReference cung cấp nhiều hơn: so sánhAndSet và getAndSet, đây là điều mà bạn không thể đạt được nếu không có đồng bộ hóa.
maaartinus

5

Trong Java, việc đọc và ghi số lượng 32 bit hoặc nhỏ hơn được đảm bảo là nguyên tử.
Theo nguyên tử, chúng tôi có nghĩa là mỗi hành động diễn ra trong một bước và không thể bị gián đoạn. Do đó, khi chúng ta có các ứng dụng đa luồng, các hoạt động đọc và ghi là an toàn theo luồng và không cần phải đồng bộ hóa.

Ví dụ: mã sau là chuỗi an toàn:

public class ThreadSafe   
  {  
    private int x;  
    public void setX(int x)  
          {
           this.x = x;
           } 
  }

5
..threadsafe theo nghĩa là giá trị sẽ luôn chính xác hoặc là giá trị ban đầu hoặc giá trị đã đặt. Hầu hết giá trị cập nhật vẫn không nhất thiết phải hiển thị cho các chủ đề khác do thiếu "biến động" hoặc "đồng bộ hóa".
Mikko Wilkman

1
+1 những gì @MikkoWilkman nói. Đoạn mã đó không nên được sử dụng vì nó chắc chắn không an toàn cho chuỗi từ góc độ khả năng hiển thị bộ nhớ.
Knuckles the Echidna

0

vẻ như các phép gán dài là nguyên tử, dựa trên phương pháp này trong AtomicLong.java:

public final void set(long newValue) {
    value = newValue;
}

Lưu ý sự vắng mặt của bất kỳ đồng bộ hóa nào.


3
Nhìn vào khai báo của value. Nó volatile.
maaartinus

2
Đó valuevolatilekhông làm cho sự phân công của valuenguyên tử, nó chỉ đơn thuần là tránh "xuất bản" vấn đề này.
Lyle Z

7
Nó thực hiện cả hai, xem JLS, mục 17.7 : Việc viết và đọc các giá trị dài và đôi dễ bay hơi luôn là nguyên tử.
maaartinus

@LyleZ nhận xét có giá trị nhất trong chủ đề này, theo ý kiến ​​của tôi.
stdout
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.