2011-10-18 37 views
43

Biến động an toàn int trong chủ đề an toàn của Java? Nghĩa là, nó có thể được đọc và ghi một cách an toàn mà không cần khóa không?Là một int dễ bay hơi trong Java thread-safe?

+0

Nếu bạn đang thay đổi dữ liệu thường xuyên thì không an toàn –

Trả lời

57

Có, bạn có thể đọc từ đó và viết thư cho nó một cách an toàn - nhưng bạn không thể làm bất cứ điều gì phức tạp như tăng nó một cách an toàn, vì đó là một chu trình đọc/sửa đổi/ghi. Ngoài ra còn có vấn đề làm thế nào nó tương tác với truy cập vào khác biến số.

Bản chất chính xác của biến động là thẳng thắn khó hiểu (xem memory model section of the JLS for more details) - Tôi sẽ cá nhân thường sử dụng AtomicInteger thay vào đó, như là một cách đơn giản hơn để đảm bảo tôi làm cho nó đúng.

+13

Bạn có thể tăng một 'biến động int' một cách an toàn, nhưng bạn sẽ cần phải thay thế' ++ 'bằng toàn bộ tải 'AtomicIntegerFieldUpdater'. (Không phải là nhanh, nhưng nếu truy cập bị chi phối bởi chi phí đọc/ghi và/hoặc bộ nhớ đơn giản là rất quan trọng, nó có thể hữu ích) –

+0

@ TomHawtin-tackline: Cảm ơn chi tiết :) –

+2

Để minh hoạ đầy đủ hơn về vấn đề ++ , Tôi đã tìm thấy http://jeremymanson.blogspot.com/2007/08/volatile-does-not-mean-atomic.html đẹp và rõ ràng. –

5

[...] như có thể đọc và ghi một cách an toàn mà không cần khóa?

Có, giá trị đọc luôn là kết quả của lần viết cuối cùng (và cả đọc và viết).

Đọc/ghi dễ bay hơi giới thiệu mối quan hệ xảy ra trước đó trong quá trình thực hiện.

Từ Java Language Specification Chapter 17: Threads and Locks

Một ghi vào một lĩnh vực dễ bay hơi (§8.3.1.4) xảy ra-trước mỗi đọc tiếp theo của lĩnh vực đó.

Nói cách khác, khi giao dịch với các biến không ổn định bạn không cần phải đồng bộ hóa một cách rõ ràng (giới thiệu một xảy ra-trước khi quan hệ) sử dụng synchronized từ khóa để đảm bảo rằng các thread được các giá trị mới nhất ghi vào biến .

Như Jon Skeet chỉ ra, việc sử dụng các biến dễ bay hơi bị hạn chế và bạn nên xem xét sử dụng các lớp học từ gói java.util.concurrent thay thế.

+0

"_when giao dịch với biến số biến động_ (...) _latest value được viết cho biến_" Và với ** non ** 'volatile' biến, không có điều như" giá trị mới nhất được ghi vào biến ". Bạn cần 'volatile' cho cụm từ" giá trị mới nhất được viết cho biến "để có ý nghĩa. – curiousguy

+0

Tôi không đồng ý. Nếu tôi làm 'x = 1; x = 2; 'trong một luồng, và sau đó' System.out.println (x) 'trong một chuỗi khác (* dài sau *' x = 2' đã được thực thi, nó vẫn có thể in '1'. Ý tôi là nếu '2' là giá trị được ghi cuối cùng bằng' x', thì 'x' có thể vẫn không đánh giá thành' 2' trong một chuỗi khác. – aioobe

+0

Nếu 'x' không phải là' biến động': "_after' x = 2' đã được thực hiện _ "/ trước khi' x = 2' đã được thực thi ** không được xác định rõ ** Nếu bạn thực sự đọc 'x' sau khi nó được đặt thành 2, thì tất nhiên bạn sẽ nhận được 2. – curiousguy

1

Quyền truy cập vào int dễ bay hơi trong Java sẽ an toàn theo luồng. Khi tôi nói truy cập tôi có nghĩa là các hoạt động đơn vị trên nó, như volatile_var = 10 hoặc int temp = volatile_var (về cơ bản ghi/đọc với các giá trị không đổi). Từ khóa dễ bay hơi trong java đảm bảo hai điều:

  1. Khi đọc bạn luôn nhận được giá trị trong bộ nhớ chính. Nói chung cho mục đích tối ưu hóa, JVM sử dụng thanh ghi hoặc trong các thuật ngữ tổng quát hơn bộ nhớ cục bộ biến lưu trữ/truy cập của kẻ thù. Vì vậy, trong môi trường đa luồng, mỗi luồng có thể thấy bản sao biến khác nhau. Nhưng làm cho nó dễ bay hơi làm cho chắc chắn rằng ghi vào biến là đỏ ửng đến bộ nhớ chính và đọc nó cũng xảy ra từ bộ nhớ chính và do đó đảm bảo rằng thread thấy ở bên phải bản sao của biến.
  2. Quyền truy cập dễ bay hơi được tự động đồng bộ hóa. Vì vậy, JVM đảm bảo đặt hàng trong khi đọc/ghi vào biến.

Tuy nhiên Jon Skeet đề cập đúng rằng trong các hoạt động không nguyên tử (volatile_var = volatile + 1) các chủ đề khác nhau có thể nhận được kết quả không mong muốn.

0

Không phải lúc nào.

Đó không phải là chủ đề an toàn nếu có nhiều chủ đề đang viết và đọc biến. Đó là chủ đề an toàn nếu bạn có một chủ đề nhà văn và nhiều chủ đề đọc.

Nếu bạn đang tìm kiếm Chủ đề một cách an toàn, sử dụng AtomicXXX lớp

Một bộ công cụ nhỏ của các lớp học có hỗ trợ lập trình thread-safe lock-free trên các biến duy nhất.

Về bản chất, các lớp trong gói này mở rộng khái niệm về giá trị, lĩnh vực, và các phần tử mảng không ổn định với những người mà còn cung cấp một hoạt động cập nhật có điều kiện nguyên tử có dạng:

boolean compareAndSet(expectedValue, updateValue); 

Tham khảo @ teto trả lời ở bên dưới bài:

Volatile boolean vs AtomicBoolean

+0

Ý của bạn là gì? "thread safe"? – curiousguy

+0

https://stackoverflow.com/questions/2033879/what-does-threadsafe-mean –

0

Nếu một biến động không phụ thuộc vào bất kỳ biến dễ bay hơi khác chủ đề của nó an toàn cho hoạt động đọc. Trong trường hợp viết dễ bay hơi thì không đảm bảo an toàn luồng.

Giả sử bạn có biến số i biến động và giá trị của nó phụ thuộc vào một biến dễ bay hơi khác nói j. Bây giờ biến truy cập Thread-1 j và tăng nó và sắp sửa cập nhật nó trong bộ nhớ chính từ bộ nhớ cache CPU. Trong trường hợp Thread-2 đọc
biến i trước khi Thread-1 thực sự có thể cập nhật j trong bộ nhớ chính. Giá trị của i sẽ theo giá trị cũ của j mà sẽ không chính xác. Nó còn được gọi là Dirty read.

0

1) Nếu hai luồng vừa đọc và ghi vào biến chia sẻ, thì sử dụng từ khóa dễ bay hơi cho điều đó là không đủ. Bạn cần sử dụng đồng bộ trong trường hợp đó để đảm bảo rằng việc đọc và viết biến là nguyên tử. Đọc hoặc viết một biến dễ bay hơi không chặn các chủ đề đọc hoặc viết. Để điều này xảy ra, bạn phải sử dụng từ khóa được đồng bộ hóa xung quanh các phần quan trọng.

2) Để thay thế cho một khối đồng bộ, bạn cũng có thể sử dụng một trong nhiều kiểu dữ liệu nguyên tử được tìm thấy trong gói java.util.concurrent. Ví dụ, AtomicLong hoặc AtomicReference hoặc một trong số những người khác.

Đó là chủ đề an toàn nếu bạn có một chuỗi chủ đề và nhiều chuỗi trình đọc.

class Foo { 
private volatile Helper helper = null; 
public Helper getHelper() { 
if (helper == null) { 
synchronized(this) { 
if (helper == null) 
helper = new Helper(); 
} 
} 
return helper; 
} 
} 

Lưu ý: Nếu người trợ giúp không thay đổi thì không cần từ khóa dễ bay hơi.Here singleton sẽ hoạt động bình thường.

Trong trường hợp bộ đếm đang được tăng lên bởi nhiều luồng (đọc thao tác viết) sẽ không trả lời đúng. Tình trạng này cũng được minh họa bằng điều kiện chủng tộc.

public class Counter{ 
private volatile int i; 
public int increment(){ 
i++; 
} 
} 

LƯU Ý: Ở đây dễ bay hơi sẽ không hữu ích.

+0

Trong Java, hãy cẩn thận phân biệt điều kiện chủng tộc và cuộc đua ** dữ liệu ** – curiousguy

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