2014-04-20 16 views
5

Tôi đọc một số bài viết về vấn đề tương tranh nhưng tôi vẫn không chắc chắn về điều gì đó. Tôi có thể nói rằng khi sử dụng đồng bộ, tôi nhận được các chức năng dễ bay hơi miễn phí, bởi vì khi khóa trên một đối tượng sẽ được giải phóng, luồng tiếp theo luôn đọc đối tượng đã sửa đổi. Với biến động, giá trị của một đối tượng được phản ánh ngay lập tức với các chủ đề khác. Nhưng khi tôi sử dụng đồng bộ, không có khả năng phản ánh ngay lập tức nó do khóa trên vật thể. Khi khóa được giải phóng, chỉ khi đó một luồng khác có thể truy cập nó. Vì vậy, tôi không phải quan tâm đến việc phản ánh giá trị ngay lập tức cho các chủ đề khác. Tôi có hiểu điều này đúng không?Java Khi sử dụng đồng bộ, tôi có nhận được chức năng dễ bay hơi không?

[UPDATE]
Ví dụ in luôn luôn 1 2 3 4 5 6 7 8 9 không dễ bay hơi.

package main; 

public class Counter 
{ 
    public static long count = 0; 
} 

public class UseCounter implements Runnable 
{ 
    public void increment() 
    { 
     synchronized (this) 
     {  
      Counter.count++; 
      System.out.print(Counter.count + " "); 
     } 
    } 

    @Override 
    public void run() 
    { 
     increment(); 
     increment(); 
     increment(); 
    } 
} 

public class DataRace 
{ 
    public static void main(String args[]) 
    { 
     UseCounter c = new UseCounter(); 

     Thread t1 = new Thread(c); 
     Thread t2 = new Thread(c); 
     Thread t3 = new Thread(c); 

     t1.start(); 
     t2.start(); 
     t3.start(); 
    } 
} 
+0

Cập nhật của bạn: Những gì nó hiện đang in khó có nghĩa là bất cứ điều gì. Các điều kiện chủng tộc dữ liệu thường lén lút khi bạn ít mong đợi chúng nhất và chúng rất khó tái tạo và giải quyết. Điều quan trọng là nếu bạn đã tuân theo các quy tắc của Mô hình bộ nhớ Java. –

+0

Ok cảm ơn. Mặc dù tôi không thể tái tạo hành vi sai trái mà không dễ bay hơi (thậm chí khi tôi chạy mã 1.000.000 lần trong một vòng lặp), tôi sẽ ghi nhớ nó. – Bevor

Trả lời

2

Không, một truy cập dễ bay hơi không được ngụ ý bởi truy cập đồng bộ theo các bộ nhớ Kiểu Java (mặc dù về việc triển khai cụ thể, nó có thể được, nhưng bạn không nên phụ thuộc vào đó)

Java Language Specification 17.4.4 (on the Java Memory Model):

Thao tác đồng bộ hóa tạo mối quan hệ đồng bộ hóa với các hành động , được xác định như sau:

  • Hành động mở khóa trên màn hình m đồng bộ hóa -với tất cả các khóa sau hành động trên m (trong đó "tiếp theo" được xác định theo thứ tự đồng bộ ).

  • Ghi vào biến dễ bay hơi v (§8.3.1.4) đồng bộ hóa với tất cả lần đọc tiếp theo v bởi bất kỳ chuỗi nào (trong đó "tiếp theo" được xác định theo thứ tự đồng bộ).

volatile hoạt động trên một biến và synchronized hoạt động trên màn hình (các 'khóa') của một đối tượng.

Nếu một chủ đề Một vừa thoát một khối đồng bộ trên đối tượng O, và chủ đề khác B vừa đọc một biến dễ bay hơi (field instance) V trên đối tượng O, sau đó vẫn là không một mối quan hệ đồng bộ giữa hai luồng. Không có gì đảm bảo rằng Thread A sẽ thấy bất kỳ sửa đổi dữ liệu nào được thực hiện bởi Thread B hoặc ngược lại, cho đến khi Thread B đồng bộ trên đối tượng O hoặc cho đến khi Thread A cũng truy cập trường bay hơi V trên đối tượng O.

+0

Ok, điều đó có nghĩa là tôi luôn luôn nên sử dụng dễ bay hơi khi truy cập các biến bên ngoài bằng một vài luồng? Xem các câu hỏi được cập nhật của tôi. Nó luôn luôn in 1 2 3 4 5 6 7 8 9 mà không dễ bay hơi. Vậy điều đó có nghĩa là nó không được đảm bảo để làm như vậy? – Bevor

+0

Khi một luồng B đọc (hoặc viết) một trường biến động sau một luồng A khác, sau đó luồng B sẽ thấy * tất cả * sửa đổi mà luồng A được tạo thành bất kỳ biến nào (trước khi nó truy cập cùng trường biến động), bao gồm cả không bay hơi những người. Việc truy cập cùng các biến dễ bay hơi tạo ra một mối quan hệ "xảy ra-trước" giữa các luồng đã làm như vậy. –

1

Biến biến động không giống với truy cập được đồng bộ hóa. Khi bạn đánh dấu một biến là biến động, Thread các đối tượng truy cập vào đối tượng sẽ không giữ bộ đệm cục bộ và sẽ chỉ có một "bản sao". Nếu bạn kết hợp hai (đồng bộ và dễ bay hơi) thì nó sẽ luôn là phiên bản cập nhật và bạn sẽ không có quyền truy cập xung đột của nó.

+0

Cảm ơn, nhưng tôi không hiểu tại sao có một truy cập xung đột, bởi vì khi tôi khóa và giải phóng một đối tượng đã đồng bộ, tôi có phải quan tâm liệu chuỗi đầu tiên có tạo bản sao cục bộ không? Khi đối tượng được mở khóa, không phải là nó sau đó đảm bảo rằng các chủ đề tiếp theo được truy cập vào đối tượng sửa đổi? – Bevor

+0

Ý tưởng đằng sau 'bay hơi' là bạn sẽ luôn nhận được phiên bản cập nhật nhất của biến. Khi một thread giữ cache, nó sẽ làm như vậy để tiết kiệm thời gian nhận các giá trị mới nhưng các biến dễ bay hơi sẽ không được lưu trữ – Rogue

0

Mã của bạn được đảm bảo in 1 2 3 4 5 6 7 8 9.Lý do là nếu bạn có một chuỗi như

  1. Chủ đề t1 ghi vào Counter.count
  2. Chủ đề t1 mở ra đối tượng c
  3. khóa Chủ đề t2 đối tượng c
  4. Chủ đề t2 đọc Counter.count

sau đó nó được đảm bảo rằng đọc ở bước 4 thấy ghi ở bước 1.

này không giống như volatile bởi vì nó không đảm bảo rằng ghi được phản ánh trở lại bộ nhớ ngay lập tức, thay vì nó chỉ đảm bảo rằng việc ghi ở bước 1 có thể nhìn thấy t2 ở cuối bước 3.

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