2012-10-31 30 views
74

Tôi đọc mã nguồn của JDK về ConcurrentHashMap.Tại sao mã nguồn JDK lấy bản sao `cuối cùng 'của các biến thể` volatile`

Nhưng đoạn mã sau nhầm lẫn tôi:

public boolean isEmpty() { 
    final Segment<K,V>[] segments = this.segments; 
    ... 
} 

Câu hỏi của tôi là:

"this.segments" được khai báo:

final Segment<K,V>[] segments; 

Vì vậy, ở đây, trong đầu , đã khai báo cùng một tham chiếu kiểu, trỏ đến cùng một bộ nhớ.

Tại sao tác giả viết nó như thế này? Tại sao họ không sử dụng trực tiếp điều này? Có lý do gì không?

Trả lời

94

Đây là một thành ngữ điển hình cho mã không có khóa liên quan đến các biến số volatile. Tại dòng đầu tiên bạn đọc volatile một lần và sau đó làm việc với nó. Trong khi đó, một chuỗi khác có thể cập nhật volatile, nhưng bạn chỉ quan tâm đến giá trị ban đầu bạn đọc.

Ngoài ra, ngay cả khi biến thành viên được đề cập không biến động nhưng cuối cùng, thành ngữ này phải làm với bộ đệm CPU khi đọc từ vị trí ngăn xếp thân thiện với bộ nhớ cache hơn là đọc từ vị trí heap ngẫu nhiên. Cũng có nhiều khả năng là var cục bộ sẽ kết thúc với một thanh ghi CPU.

Đối với trường hợp thứ hai này, thực sự có một số tranh cãi, vì trình biên dịch JIT thường sẽ xử lý những mối quan tâm đó, nhưng Doug Lea là một trong những kẻ bám theo nguyên tắc chung.

+0

Vì vậy, nếu ai đó thay đổi nội dung 'this.segments' này, bạn sẽ không thấy thay đổi đó trong' phân đoạn' của mình? – brimborium

+0

Tất nhiên bạn sẽ thấy nó. Nhưng nếu ai đó gán cái gì đó khác cho 'phân đoạn', bạn rõ ràng sẽ bị cô lập khỏi điều đó. –

+3

Ah vâng, chắc chắn rồi. Missunderstood câu trả lời của bạn ...;) – brimborium

19

Tôi đoán đó là để xem xét hiệu suất, do đó chúng tôi chỉ cần truy xuất giá trị trường một lần.

Bạn có thể tham khảo một thành ngữ singleton từ java hiệu quả bởi Joshua Bloch

singleton của ông là ở đây:

private volatile FieldType field; 
FieldType getField() { 
    FieldType result = field; 
    if (result == null) { 
    synchronized(this) { 
     result = field; 
     if (result == null) 
     field = result = computeFieldValue(); 
    } 
    } 
    return result; 
} 

và ông viết:

Mã này có thể xuất hiện một chút phức tạp. Đặc biệt, nhu cầu về kết quả biến cục bộ có thể không rõ ràng. Biến số này là gì để đảm bảo rằng trường chỉ được đọc một lần trong trường hợp thông thường là đã được khởi tạo. Mặc dù không thực sự cần thiết, điều này có thể cải thiện hiệu suất và thanh lịch hơn theo các tiêu chuẩn được áp dụng cho lập trình đồng thời cấp thấp . Trên máy của tôi, phương pháp trên là khoảng 25 phần trăm nhanh hơn phiên bản hiển thị mà không có biến cục bộ.

+0

+1 để trích dẫn nguồn. –

4

Nó có thể làm giảm kích thước mã byte - truy cập vào một biến cục bộ ngắn hơn trong mã byte hơn là truy cập một biến mẫu.

Chi phí tối ưu hóa thời gian chạy cũng có thể bị giảm.

Nhưng không cái nào trong số này là quan trọng. Đó là nhiều hơn về phong cách mã. Nếu bạn cảm thấy thoải mái với các biến mẫu, bằng mọi cách.Doug Lea có lẽ là cảm thấy thoải mái hơn khi xử lý các biến cục bộ.

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