2011-09-26 16 views
15

Phương pháp AtomicXXX.lazySet (giá trị) có nghĩa là gì xảy ra trước các cạnh, được sử dụng trong hầu hết các lý do JMM? Các javadocs là tinh khiết vào nó, và Sun lỗi 6275329 trạng thái:AtomicXXX.lazySet (...) về mặt xảy ra trước các cạnh

Ngữ nghĩa là rằng ghi được đảm bảo không để được sắp xếp lại với bất kỳ ghi trước đó, nhưng có thể được sắp xếp lại với các hoạt động tiếp theo (hoặc tương đương, có thể không hiển thị với các chủ đề khác) cho đến khi một số hành động ghi hoặc đồng bộ dễ bay hơi khác xảy ra).

Nhưng đây không phải là lý do về các cạnh HB, do đó, nó gây nhầm lẫn cho tôi. Có nghĩa là những gì lazySet() ngữ nghĩa không thể được thể hiện trong điều khoản của HB cạnh?

CẬP NHẬT: Tôi sẽ cố gắng cụ thể hoá câu hỏi của mình. Tôi có thể sử dụng trường biến động bình thường trong tình huống sau:

//thread 1: producer 
...fill some data structure 
myVolatileFlag = 1; 

//thread 2: consumer 
while(myVolatileFlag!=1){ 
    //spin-wait 
} 
...use data structure... 

Trong này sử dụng kịch bản của "cấu trúc dữ liệu" trong tiêu dùng là đúng, vì cờ biến động ghi-đọc làm HB cạnh, cho đảm bảo tất cả những gì viết để "cấu trúc dữ liệu "bởi nhà sản xuất sẽ được hoàn thành và được người tiêu dùng nhìn thấy. Nhưng nếu tôi sử dụng AtomicInteger.lazySet/get thay vì viết/đọc dễ bay hơi trong trường hợp này thì sao?

//thread 1: producer 
...fill some data structure 
myAtomicFlag.lazySet(1); 

//thread 2: consumer 
while(myAtomicFlag.get()!=1){ 
    //spin-wait 
} 
...use data structure... 

sẽ vẫn đúng không? Tôi vẫn có thể thực sự hiển thị giá trị "cấu trúc dữ liệu" trong chuỗi tiêu thụ?

Nó không phải là "từ trên không" câu hỏi - Tôi đã nhìn thấy phương pháp như vậy trong Lmax đang Disruptor chính xác tình huống này, và tôi không hiểu làm thế nào để chứng minh điều đó là đúng ...

+0

nếu phương thức lazySet đóng vai trò là hàng rào cửa hàng, bạn có thể sử dụng nó. Khi thread2 thấy cờ nó sẽ là ok để đọc cấu trúc. Các lazySet đảm bảo viết sẽ được hiển thị tại một số điểm và tất cả các kiến ​​trúc cho phép hiển thị tự động, tức là nếu một cái gì đó nó được viết nó sẽ được hiển thị và cuối cùng phù hợp. – bestsss

Trả lời

10

Các hoạt động lazySet không tạo ra xảy ra trước khi các cạnh và do đó không được đảm bảo hiển thị ngay lập tức. Đây là một tối ưu hóa ở mức độ thấp chỉ có một vài trường hợp sử dụng, phần lớn là trong các cấu trúc dữ liệu đồng thời.

Ví dụ về thu thập rác của việc loại bỏ các con trỏ danh sách được liên kết không có tác dụng phụ có thể nhìn thấy của người dùng. Các nulling được ưa thích để nếu các nút trong danh sách là trong các thế hệ khác nhau, nó không buộc một bộ sưu tập đắt tiền hơn được thực hiện để loại bỏ các chuỗi liên kết.Việc sử dụng lazySet duy trì ngữ nghĩa hygenic mà không phải chịu chi phí viết trên bay hơi.

Ví dụ khác là việc sử dụng các trường dễ bay hơi được bảo vệ bởi khóa, chẳng hạn như trong ConcurrentHashMap. Các trường là dễ bay hơi để cho phép đọc không khóa, nhưng việc ghi phải được thực hiện dưới một khóa để đảm bảo tính nhất quán nghiêm ngặt. Khi khóa đảm bảo xảy ra trước khi cạnh được phát hành, tối ưu hóa là sử dụng lazySet khi ghi vào các trường và xóa tất cả các cập nhật khi mở khóa. Điều này giúp giữ cho phần quan trọng ngắn bằng cách tránh các quầy hàng không cần thiết và lưu lượng xe buýt.

Nếu bạn viết một cấu trúc dữ liệu đồng thời thì lazySet là một mẹo hay cần lưu ý. Đó là một tối ưu hóa ở mức độ thấp vì vậy nó chỉ đáng xem xét khi điều chỉnh hiệu suất.

+0

Cảm ơn bạn đã làm rõ. Bạn cũng có thể xem xét cập nhật và bình luận không? – BegemoT

+0

Là một bộ, không phải là một nhóm, chỉ an toàn khi nó không ghi đè lên dữ liệu quan trọng khi được hiển thị. Nhiều nhà sản xuất sẽ cạnh tranh cho một khe, vì vậy nó không an toàn. Sẽ an toàn nếu một người tiêu dùng duy nhất rút bộ đệm ra, trì hoãn khả năng hiển thị của một khe trống. Tôi đã chơi với điều đó một vài tháng trước, hãy xem [ring buffer] của tôi (http://code.google.com/p/concurrentlinkedhashmap/source/browse/trunk/src/main/java/com/googlecode/concurrentlinkedhashmap/RingBuffer .java? spec = svn754 & r = 749) mã. –

+0

Đây là trường hợp sản xuất đơn lẻ/đơn lẻ. Nhưng tôi vẫn không hiểu tại sao nó là an toàn - làm thế nào để tôi có thể chứng minh những gì 1) viết được thực hiện trước khi sequence.lazySet (seq) là tất cả đã hoàn thành và _visible_ đến thread 2 sau khi sequence.get() == seq? và 2) lazySet (seq) thực sự được viết ở một số thời điểm hữu hạn: tài liệu nói "cuối cùng" - có thể có nghĩa là "trong giây", "tính theo giờ" và thậm chí là "không bao giờ". Nếu nhìn vào lazySet như không dễ bay hơi, có vẻ như nó có thể tự do bị trì hoãn mãi mãi bởi trình biên dịch hoặc bộ xử lý ... – BegemoT

3

Dựa trên Javadoc của không an toàn (các putOrderedInt được sử dụng trong AtomicInteger.lazySet)

/** 
* Version of {@link #putObjectVolatile(Object, long, Object)} 
* that does not guarantee immediate visibility of the store to 
* other threads. This method is generally only useful if the 
* underlying field is a Java volatile (or if an array cell, one 
* that is otherwise only accessed using volatile accesses). 
*/ 
public native void putOrderedObject(Object o, long offset, Object x); 

/** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */ 
public native void putOrderedInt(Object o, long offset, int x); 

các trường ủng hộ trong các lớp AtomicXXX là dễ bay hơi. Các lazySet dường như viết cho các lĩnh vực này như thể họ không phải là dễ bay hơi, mà sẽ loại bỏ các xảy ra trước khi các cạnh bạn đang mong đợi. Như đã lưu ý trong liên kết của bạn, điều này sẽ hữu ích cho việc nulling các giá trị để đủ điều kiện cho GC mà không cần phải viết ghi dễ bay hơi.

Chỉnh sửa:

Điều này nhằm trả lời cập nhật của bạn.

Nếu bạn xem báo giá bạn đã cung cấp từ liên kết thì bạn sẽ mất mọi bộ nhớ đảm bảo bạn có với ghi dễ bay hơi.

lazySet sẽ không được đặt hàng ở trên nơi nó được ghi vào, nhưng không có bất kỳ đồng bộ hóa thực tế nào khác, bạn mất bảo đảm rằng người tiêu dùng sẽ thấy bất kỳ thay đổi nào được viết trước đó. Nó là hoàn toàn hợp pháp để trì hoãn việc viết của myAtomicFlag và có cho bất kỳ viết trước khi nó cho đến khi một số hình thức đồng bộ hóa khác xảy ra.

+0

lazySet đảm bảo không viết lại trật tự, nhưng không làm như vậy để đọc một, tức là lần đọc liên tiếp có thể được thực hiện trước khi giá trị được truyền đi. cho x86 lazySet chỉ là một lệnh mov. Trong ví dụ trên, lazySet là tốt, imo ... và đó là chiến thắng tuyệt vời. – bestsss

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