2010-03-05 22 views
5

Trong Java có tồn tại một lớp AtomicReference. Điều này có nghĩa là thiết lập một tham chiếu KHÔNG phải là một hoạt động nguyên tử trong và của chính nó?AtomicReference trong Java - cần thiết để thiết lập tham chiếu trong môi trường an toàn cho luồng?

ví dụ, là đây không phải thread-safe (giả định rằng giá trị trả về không thể được sửa đổi) ?:

public void someMethod() 
{ 
    this.someList = Collections.unmodifiableList(new LinkedList<Object>()); 
} 

public List<Object> getReadOnlyList() 
{ 
    return someList; 
} 

Làm thế nào về trong C#?

+3

Ví dụ của bạn không hoàn toàn an toàn cho chuỗi. Nếu danh sách được xuất bản không đúng, bạn có thể không đọc đúng nội dung (mặc dù việc thực hiện 'LinkedList' có thể cho phép bạn thoát khỏi điều này nếu nó trống). –

+0

@Tom: bạn có nghĩa là các chủ đề khác có thể nhận được giá trị cũ, được lưu trong bộ nhớ cache cho trường someList hoặc trường someList có thể thực sự được "viết một nửa" không? – radai

+0

@ hatchetman82 Tôi có nghĩa là sau khi tài liệu tham khảo mới được đọc, đối tượng nó trỏ đến có thể không được cập nhật hoàn toàn. Vì vậy, nếu tôi không công khai 'java.awt.Point (1, 2) 'mới, tôi có thể đọc đối tượng trong một luồng khác nhưng các trường' x' và 'y' vẫn có thể bằng không. –

Trả lời

3

Theo Java Language Specification, version 3.0, Section 17.7:

viết thư cho và đọc tài liệu tham khảo luôn nguyên tử, bất kể họ đang thực hiện giá trị như 32 hoặc 64 bit.

AtomicReference cho phép thực hiện so sánh và đặt làm tác vụ nguyên tử.

Đây không phải là thread:

public boolean changeList(List<Object> oldValue, List<Object> newValue) { 
    if (this.someList == oldValue) { 
     // someList could be changed by another thread after that compare, 
     // and before this set 
     this.someList = newValue; 
     return true; 
    } 
    return false; 
} 
+1

Có thể thực hiện với một số generics trong tham số 'List'. –

+0

sử dụng công khai boolean changeList (Danh sách oldValue, Danh sách newValue) thay vì – Lombo

1

Nếu bạn không sử dụng AtomicReference hoặc từ khóa dễ bay hơi và các chủ đề đọc tài liệu tham khảo không phải là một trong đó đã viết thư cho nó, không có gì bảo đảm rằng việc đọc chuỗi sẽ thấy giá trị được cập nhật.

Điều này đặc biệt đúng trong môi trường đa bộ xử lý. Từ khóa dễ bay hơi và AtomicReference (sử dụng dễ bay hơi trong nội bộ cho các hoạt động thiết lập/nhận cơ bản) thực thi một hàng rào bộ nhớ và bộ đệm ẩn để đảm bảo rằng giá trị cập nhật hiển thị trong bộ nhớ chính.

3

Đôi khi bị bỏ qua package description cho java.util.concurrent.atomic xây dựng trên một số ứng dụng phổ biến.

Hợp đồng bổ sung: Tương tự, package description cho java.util.concurrent thuận tiện tóm tắt một số điểm quan trọng được nêu chi tiết trong JLS §17.

Ngoài ra, hãy xem xét lợi ích tiềm năng của Final Field Semantics nếu List của bạn có nghĩa là không thay đổi và tham chiếu đến nó có thể được thực hiện final.

1

Theo như C#, tôi đã tìm thấy câu trả lời cho chính bản thân mình. Đặt tham chiếu là một hoạt động nguyên tử theo phần 5.5 của đặc tả ngôn ngữ C#.

"Đọc và ghi các loại dữ liệu sau là nguyên tử: bool, char, byte, sbyte, ngắn, ushort, uint, int, float và các loại tham chiếu. Ngoài ra, đọc và viết các loại enum với một cơ sở Đọc và viết các loại khác, bao gồm cả dài, ulong, đôi và thập phân, cũng như các loại do người dùng định nghĩa, không được đảm bảo là nguyên tử. Ngoài các chức năng thư viện được thiết kế cho mục đích đó , không có sự đảm bảo về nguyên tử đọc-sửa đổi-ghi, chẳng hạn như trong trường hợp tăng hoặc giảm. "

+0

Câu hỏi là về an toàn luồng chứ không phải nguyên tử. Ví dụ: việc đọc biến tham chiếu không được đồng bộ hóa trong Java có thể là nguyên tử nhưng ** không ** an toàn luồng. –

+0

Cf. http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.7 – trashgod

+0

Điểm là nguyên tử đảm bảo bạn sẽ đọc giá trị cũ của tham chiếu (hoặc null) hoặc giá trị mới của tài liệu tham khảo nhưng không bao giờ là một phần của một phần khác. –

3

Điều này có nghĩa là việc đặt tham chiếu KHÔNG phải là một hoạt động nguyên tử trong và của chính nó?

Đặt biến tham chiếu là nguyên tử, nhưng thao tác nguyên tử không nhất thiết phải an toàn theo luồng. Hãy để tôi giải thích.

Nguyên tử có nghĩa là bất kỳ người quan sát nào (chủ đề) đều thấy giá trị cũ hoặc giá trị mới của biến và không phải cái gì khác. Nó không có nghĩa là tất cả các nhà quan sát thấy giá trị mới khi họ nhìn vào biến. (Và như @Tom chỉ ra, nguyên tử của biến tham chiếu không nói gì về tính chất nguyên tử của đối tượng mà nó tham chiếu.)

Đối với tất cả các nhà quan sát thấy giá trị mới trong biến, cần có sự đồng bộ hóa nào đó trên. Đối với một bản cập nhật cho một biến, điều này sẽ xảy ra nếu:

  • biến được khai báo là volatile, hoặc
  • truy cập/cập nhật vào biến được đồng bộ hóa bằng khóa màn hình nguyên thủy giống nhau.

Một biến được bao bọc trong "AtomicXxx" class có liên quan cũng sẽ được thread-an toàn, mặc dù bạn vẫn thường sử dụng một trong các lớp này nếu bạn muốn tránh ổ khóa bạn muốn làm những thứ như nguyên tử "so sánh và thay thế".

Một lần nữa, điều này chỉ áp dụng cho tính an toàn của chủ đề của tham chiếu đối tượng. Nếu trạng thái của đối tượng không phải là cũng được đồng bộ hóa đúng cách, một luồng cũng có thể thấy giá trị cũ cho thuộc tính của đối tượng, v.v.

Các vấn đề liên quan