2014-11-04 16 views
7

Trường hợp sử dụng của tôi yêu cầu được phân bổ trực tiếp ByteBuffer được ghi một lần và sau đó được đọc bởi nhiều chủ đề đồng thời. Tất cả các lần đọc là tuyệt đối và vì vậy tôi không bao giờ quan tâm đến trạng thái của bộ đệm (vị trí, giới hạn, dấu).Tại sao đọc tuyệt đối từ một ByteBuffer không được coi là an toàn thread?

This article trên bộ đệm byte bởi Keith Gregory cảnh báo rằng thậm chí tuyệt đối đọc không được coi là thread-safe:

ByteBuffer chủ đề an toàn được bao phủ trong Buffer javadoc; phiên bản ngắn gọn là các bộ đệm không phải là chủ đề an toàn. Rõ ràng, bạn không thể sử dụng định vị tương đối từ nhiều luồng không có điều kiện chủng tộc, nhưng thậm chí vị trí tuyệt đối không được đảm bảo (bất kể bạn nghĩ gì sau khi xem các lớp triển khai).

(tôi nhấn mạnh)

Do cảnh báo này, tôi trước mỗi việc đọc từ bộ đệm byte với một cuộc gọi đến duplicate. Điều này là dễ dàng đủ, nhưng phân bổ đối tượng bổ sung trên mỗi đọc duy nhất có tôi tò mò tại sao nó thực sự cần thiết.

Mặc dù từ chối trách nhiệm wizardly Keith, tôi đã nhìn vào OpenJDK của implementation của một đọc tuyệt đối từ một bộ đệm byte trực tiếp:

public byte get(int i) { 
    return ((unsafe.getByte(ix(checkIndex(i))))); 
} 

Bạn có thể thấy rằng nó chỉ đơn giản là đại biểu Unsafe.getByte(long), mà "lấy một giá trị từ một định địa chỉ bộ nhớ ".

Tôi hiểu rằng các triển khai khác nhau có thể tồn tại, nhưng điều gì không thể an toàn cho luồng về hoạt động này một cách hợp lý? Hợp đồng Buffer có đơn giản từ chối đảm bảo an toàn luồng cho các lần đọc tuyệt đối để tránh sự nhầm lẫn của một lớp an toàn một phần không? Hoặc nếu cảnh báo được biện minh cho việc ghi đồng thời, thì tình trạng của tôi, trong đó bộ đệm byte là chưa sửa đổi sau khi tạo? Ngoài ra, bất cứ điều gì sẽ thay đổi khi sử dụng một số MappedByteBuffer thay thế?

liên quan:

+0

Hmm. Rất nhiều ý kiến ​​không được chứng minh ở đó.Ví dụ: "Tôi không nghĩ rằng điều này sẽ đưa mô hình bộ nhớ Java vào tài khoản". Việc thực hiện * phải * (a) tuân thủ đặc tả được nêu trong Javadoc và (b) đưa mô hình bộ nhớ Java vào tài khoản khi thực hiện điều đó. – EJP

+0

@EJP Nhận xét về Mô hình Bộ nhớ Java dường như đề cập đến các bộ đệm trực tiếp, nằm bên ngoài vùng heap Java. Về cơ bản chúng là các phép toán IO được ánh xạ trên bộ nhớ, và các thao tác IO trên các tệp (hoặc bất kỳ thứ gì bên ngoài vùng/ngăn xếp Java/v.v.) không phải tuân theo mô hình Bộ nhớ Java –

+0

Ngay cả khi bỏ qua các vấn đề hiển thị bạn sẽ nhận được mà không cần đồng bộ hóa thích hợp, phương thức 'get' không phải là nguyên tử. Nó truy cập mảng dữ liệu được chia sẻ và thực hiện kiểm tra chỉ mục bao gồm việc đọc trạng thái chia sẻ 'giới hạn'. – isnot2bad

Trả lời

-1

Đối với một trạng thái tài liệu đệm mà truy cập vào bộ đệm nên được đồng bộ. Nó không nói rằng nó không được sử dụng bởi các chủ đề khác nhau. Vì vậy, tôi nghĩ rằng duplicate là không cần thiết.

Điều đó bạn không thể nghĩ ra việc triển khai không an toàn hợp lý của một số phương pháp hay cách khác là giới hạn của trí tưởng tượng của bạn hơn là bằng chứng cho thấy thận trọng là không cần thiết. Đặc biệt là xem xét rằng bạn đã không nhìn vào mã Java Java, khi nó được Oracle nói rằng việc thực hiện không phải là threadsafe.

Lời khuyên của tôi: thực hiện đồng bộ hóa hợp lý khi truy cập bộ đệm. Ngay cả khi không bao giờ có một triển khai không an toàn, nó sẽ không tốn nhiều tiền cho bạn.

+2

Tôi thích sử dụng 'trùng lặp' hơn đồng bộ hóa để tránh tranh chấp. Thật không may đoạn giữa của bạn là nhiều hơn một bình luận hơn là một câu trả lời - tôi thiếu bằng chứng và trí tưởng tượng hạn chế là lý do tại sao tôi hỏi câu hỏi. –

+0

@Paul cũng có trường hợp rõ ràng về việc triển khai đọc/ghi một byte tại một thời điểm sẽ dẫn đến rách đọc/ghi. – Voo

+0

@Paul 'duplicate' chính nó không phải là chủ đề an toàn, vì vậy bạn có thể không sử dụng nó từ các chủ đề khác nhau mà không đồng bộ hóa thích hợp quá. – isnot2bad

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