2012-03-26 6 views
7

Từ cuốn sách "Java Concurrency in Practice" trang 26:Làm thế nào để hiểu "Biến không tham gia vào bất biến với các biến trạng thái khác khi sử dụng từ khóa dễ bay hơi"?

Bạn có thể sử dụng các biến không ổn định chỉ khi tất cả các tiêu chuẩn sau đây được đáp ứng:

  • Viết vào biến không phụ thuộc vào giá trị hiện tại của nó Hoặc bạn có thể đảm bảo rằng chỉ một luồng duy nhất mới cập nhật giá trị;

  • Biến thể không tham gia vào bất biến với các biến trạng thái khác; và

  • Không bắt buộc phải khóa vì bất kỳ lý do nào khác trong khi biến đang được truy cập.

Làm thế nào để hiểu được "Biến không tham gia vào bất biến với biến trạng thái khác khi sử dụng từ khóa volatile"?

+0

Một số ngữ cảnh khác sẽ hữu ích, nếu không tôi sẽ chỉ đoán ý nghĩa của nó. –

+0

Xin lỗi, tôi đã thêm ngữ cảnh bây giờ –

+0

Trong cuốn sách của tôi là 39 trang – gstackoverflow

Trả lời

15

Định nghĩa đơn giản về "bất biến": điều kiện luôn đúng trong suốt thời gian tồn tại của đối tượng.

Volatile variables do not share the atomicity features of synchronized blocks.

Đó là lý do tại sao bạn không thể sử dụng chúng trong lớp có bất biến liên quan đến nhiều biến.

Ví dụ: giả sử bạn có một class để lập mô hình khoảng thời gian được mô tả bởi hai biến: startend. Một điều kiện bất biến có thể là start luôn nhỏ hơn hoặc bằng end. Nếu cả hai biến (như ví dụ) được khai báo là dễ bay hơi thì bạn có thể dựa vào các tính năng hiển thị của volatile nhưng bạn không thể chắc chắn rằng trong một thay đổi liên quan đến cả hai biến thì bất biến luôn được thỏa mãn. Hãy suy nghĩ:

public void setInterval(Date newStart, Date newEnd) 
{ 
// Check if inputs are correct 

// Here the object state is valid 
start = newStart; 

// If another thread accesses this object now it will 
// see an invalid state because start could be greater than end 

end = newEnd; 
// Here the object state is valid again 
} 

Trong trường hợp này bạn có thể chắc chắn rằng thay đổi hiển thị cho mọi chuỗi nhưng ở giữa hai hướng, trạng thái đối tượng có thể không hợp lệ. Bởi vì nó có thể được truy cập bởi các chủ đề khác (hãy nhớ đây là một trường hợp đơn giản vì vậy nó có thể nhưng không có khả năng) thì điều kiện bất biến "bắt đầu < kết thúc" có thể bị hỏng.

Đó là lý do tại sao việc sử dụng dễ bay hơi bằng cách nào đó không được khuyến khích bên ngoài một tập hợp các mẫu được xác định rõ. Chỉ nên sử dụng biến dễ bay hơi nếu các điều kiện này được thỏa mãn:

  • Biến không liên quan đến bất biến liên quan đến các biến khác (vì lý do được giải thích ở trên).
  • Giá trị để viết trên biến không phụ thuộc vào giá trị hiện tại của nó.

Ví dụ biểu thức int a = i++; không phải là nguyên tử sau đó nó không phải - nói đúng - thread-an toàn vì nó sẽ được viết lại với một cái gì đó như thế này:

int temp = i; 
i = i + 1; 
int a = temp; 

Để làm cho nó nguyên tử từ một quan điểm chủ đề, bạn có thể tưởng tượng một lớp học như thế này:

public class MyAtomicInteger 
{ 
    public synchronized increment() 
    { 
    x = x + 1; 
    } 

    private int x; 
} 

Tất nhiên nó tồn tại đúng thực tế ntation của AtomicInteger này và nó là một phần của gói java.util.concurrent.atomic, nó cung cấp một số thói quen cơ bản đơn giản cho lập trình đồng thời không khóa.

+0

Có lỗi: nó không phải 'i = i + 1' nhưng' i = temp + 1' trong mẫu tăng 'i' của bạn, nếu không dẫn đến các câu lệnh vô hạn vì 'i = i + 1' giống như hoạt động' i ++ '. – Mik378

+0

@ Mik378 trước khi tăng "i == temp" để "i = i + 1" tương đương với "i = temp + 1". Đó là cách "++" được mở rộng không phải là "+" sau đó "i + 1" sẽ không được mở rộng một lần nữa –

+0

Hiểu, cảm ơn. – Mik378