2010-11-15 39 views
7

Đây là Java 1.6 lớp học của tôi:"Đồng bộ hóa không nhất quán" có nghĩa là gì?

public class Foo { 
    private ArrayList<String> names; 
    public void scan() { 
    if (names == null) { 
     synchronized (this) { 
     this.names = new ArrayList<String>(); 
     // fill the array with data 
     } 
    } 
    } 
} 

FindBugs nói:

Inconsistent synchronization of com.XXX.Foo.names; locked 40% of time 

có nghĩa là gì và những gì tôi đang làm sai? Tôi đang cố gắng tránh các vấn đề khi hai hoặc nhiều khách hàng gọi Foo.scan() cùng một lúc.

Trả lời

15

Thật tuyệt khi bạn chỉ đồng bộ hóa khi bạn đặt biến số names chứ không phải khi bạn đọc. Vì vậy, giữa đọc và viết một thread khác có thể thực hiện và bạn sẽ tạo ra hai ArrayLists và điền chúng với dữ liệu, cái đầu tiên được tạo ra sẽ nhận được GC'ed.

Bạn cần đặt khối đồng bộ xung quanh phần đọc và ghi hoặc thêm công cụ sửa đổi được đồng bộ hóa vào phương thức.

public class Foo { 
    private ArrayList<String> names; 
    public void scan() { 
     synchronized (this) 
     if (names == null) { 
      this.names = new ArrayList<String>(); 
      // fill the array with data 
     } 
     } 
    } 
    } 
+1

Nếu bạn dự định sử dụng thành ngữ này, biến tên phải được đánh dấu dễ bay hơi. –

+0

Bạn cũng nên kiểm tra xem nếu 'tên' là null trước khi bạn nhập khối sychrnoize. Điều này tránh khóa khi không cần thiết. – Jeremy

+0

@Phil M tại sao tên nên được đánh dấu dễ bay hơi? Tôi nghĩ rằng synchonized cung cấp khả năng hiển thị tương tự như dễ bay hơi. Vì vậy, bạn sẽ không thêm bất cứ điều gì miễn là tất cả các truy cập vào tên sử dụng cùng một khóa. – brain

6

Lần đầu tiên bạn tham khảo names bên scan nằm ngoài synchronized khối.
Ví dụ: nếu scan được gọi hai lần từ hai chủ đề khác nhau và names là null, nó có thể đi như thế này

  1. if (names == null) từ sợi đầu tiên được xử lý (để true).
  2. if (names == null) từ chuỗi thứ hai được xử lý (đến true).
  3. Chuỗi đầu tiên đi vào khối synchronized, gán names và để lại khối synchronized.
  4. Chuỗi thứ hai đi vào khối synchronized, gán names và để lại khối synchronized.

Hiện tại, names được khởi tạo hai lần. Và đây chỉ là một kịch bản có thể xảy ra khi bạn nhận được kết quả không mong muốn.

+0

'bị khóa 40% thời gian', nó có ý nghĩa gì trong cảnh báo –

+0

@ org.life.java Không có ý tưởng, có lẽ đây không phải là toàn bộ mã. –

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