2014-10-28 11 views
6

Vào khoảng đáy của http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html, nó nói:Tại sao đối tượng không thể thay thế được an toàn trong khóa đôi được kiểm tra?

đúp Checked Locking Immutable Objects

Nếu Helper là một đối tượng bất biến, chẳng hạn rằng tất cả các lĩnh vực Helper là cuối cùng, sau đó kích đúp khóa được kiểm tra sẽ hoạt động mà không cần phải sử dụng các trường dễ bay hơi. Ý tưởng là một tham chiếu đến một đối tượng bất biến (chẳng hạn như một String hoặc một số nguyên) nên hành xử theo cùng cách với int hoặc float; đọc và viết tham chiếu đến các đối tượng bất biến là nguyên tử.

Các mẫu và giải thích về một thể thay đổi như sau:

// Broken multithreaded version 
// "Double-Checked Locking" idiom 
class Foo { 
    private Helper helper = null; 
    public Helper getHelper() { 
    if (helper == null) 
     synchronized(this) { 
     if (helper == null) 
      helper = new Helper(); 
     }  
    return helper; 
    } 
    // other functions and members... 
    } 

Lý do đầu tiên nó không hoạt động

Lý do rõ ràng nhất nó không làm việc với nó rằng việc viết khởi tạo đối tượng Helper và ghi vào trường trợ giúp có thể được thực hiện hoặc nhận ra theo thứ tự. Do đó, một thread gọi getHelper() có thể thấy một tham chiếu không null đối với một đối tượng trợ giúp, nhưng xem các giá trị mặc định cho các trường của đối tượng trợ giúp, thay vì các giá trị được đặt trong hàm tạo.

Nếu trình biên dịch inlines cuộc gọi đến các nhà xây dựng, thì viết rằng khởi tạo đối tượng và ghi vào lĩnh vực trợ giúp có thể được sắp xếp lại một cách tự do nếu trình biên dịch có thể chứng minh rằng các nhà xây dựng không thể ném một ngoại lệ hoặc thực hiện đồng bộ hóa. Ngay cả khi trình biên dịch không sắp xếp lại các ghi đó, trên bộ xử lý đa bộ xử lý hoặc hệ thống bộ nhớ có thể sắp xếp lại các ghi đó, như được nhận biết bởi một luồng đang chạy trên một bộ xử lý khác.

Câu hỏi của tôi là: tại sao lớp không thay đổi không có vấn đề? Tôi không thể thấy bất kỳ mối quan hệ nào của việc sắp xếp lại với liệu lớp đó có thể thay đổi được hay không.

Cảm ơn

Trả lời

0

Các lớp không thay đổi có vấn đề. Phần mà bạn đã trích dẫn là đúng sau khi thay đổi đối với Bộ nhớ Java đã được thực hiện trong JSR133.

Cụ thể là những thay đổi ảnh hưởng đến các đối tượng không thay đổi có liên quan đến một số thay đổi đã được thực hiện đối với từ khóa final. Thanh toán http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRight.

Phần quan trọng là:

Các giá trị cho các lĩnh vực thức của một đối tượng được thiết lập trong constructor của nó. Giả sử đối tượng được xây dựng "đúng", khi một đối tượng được xây dựng, các giá trị được gán cho các trường cuối cùng trong hàm tạo sẽ được hiển thị cho tất cả các luồng khác mà không đồng bộ hóa.

1

Lý do tại sao mã là "gãy" cho các đối tượng thông thường là helper có thể là không null nhưng điểm đến một đối tượng mà vẫn chưa hoàn toàn khởi chưa như được giải thích trong báo giá của bạn.

Tuy nhiên, nếu lớp Helper là không thay đổi, nghĩa là tất cả các lĩnh vực của nó là cuối cùng, the Java Memory Model đảm bảo rằng họ được công bố một cách an toàn ngay cả khi đối tượng được tạo sẵn thông qua một cuộc chạy đua dữ liệu (đó là trường hợp trong ví dụ của bạn):

Các trường

final cũng cho phép các lập trình viên triển khai các đối tượng không thay đổi được an toàn cho chủ đề mà không đồng bộ hóa. Một đối tượng bất biến an toàn chủ đề được xem là bất biến bởi tất cả các chuỗi, ngay cả khi một cuộc đua dữ liệu được sử dụng để chuyển tham chiếu đến đối tượng bất biến giữa các chủ đề. Điều này có thể cung cấp bảo đảm an toàn chống lạm dụng một lớp không thể thay đổi bằng mã không chính xác hoặc mã độc. Các trường final phải được sử dụng chính xác để đảm bảo tính bất biến.

+0

Tôi nghĩ cụm từ "hoàn toàn khởi tạo" có nghĩa là điều gì đó khác với cụm từ trong liên kết của bạn? Một đối tượng có thể chỉ nhìn thấy một tham chiếu đến một đối tượng sau khi đối tượng đó đã được khởi tạo hoàn toàn được đảm bảo để xem các giá trị được khởi tạo chính xác cho các trường cuối cùng của đối tượng đó. " –

+0

Không có gì giống nhau: sau khi gọi đến "new Helper()', JMM đảm bảo rằng các trường cuối cùng đã được khởi tạo nhưng không nói bất cứ điều gì về các trường thông thường có thể có hoặc không được khởi tạo. – assylias

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