Giả sử tôi có một trường được truy cập đồng thời và nó được đọc nhiều lần và hiếm khi được viết.
public Object myRef = new Object();
Giả sử một Chủ đề T1 sẽ đặt myRef thành một giá trị khác, mỗi phút một lần, trong khi N Chủ đề khác sẽ đọc myRef hàng tỷ lần liên tục và đồng thời. Tôi chỉ cần rằng myRef cuối cùng sẽ hiển thị cho tất cả các chủ đề.
Một giải pháp đơn giản là sử dụng AtomicReference hoặc đơn giản là dễ bay hơi như thế này:
public volatile Object myRef = new Object();
Tuy nhiên, afaik đọc không ổn định làm phát sinh chi phí hiệu suất. Tôi biết nó rất nhỏ, nó giống như một thứ tôi tự hỏi hơn là thứ tôi thực sự cần. Vì vậy, chúng ta đừng quan tâm đến hiệu suất và cho rằng đây là một câu hỏi lý thuyết đơn thuần.
Vì vậy, câu hỏi đặt ra: Có cách nào để bỏ qua các lần đọc dễ bay hơi cho các tài liệu tham khảo mà hiếm khi được viết ra, bằng cách làm một cái gì đó tại trang web viết không?
Sau khi đọc, có vẻ như rào cản bộ nhớ có thể là thứ tôi cần. Vì vậy, nếu một cấu trúc như thế này tồn tại, vấn đề của tôi sẽ được giải quyết:
- Viết
- Gọi rào cản (đồng bộ hóa)
- Tất cả mọi thứ được đồng bộ hóa và tất cả các chủ đề sẽ thấy giá trị mới. (không có chi phí cố định tại các trang web đọc, nó có thể cũ hoặc phải chịu chi phí một lần vì bộ nhớ cache được đồng bộ hóa, nhưng sau đó tất cả trở lại trường thông thường cho đến lần ghi tiếp theo).
Có một cấu trúc như vậy trong Java, hay nói chung? Tại thời điểm này tôi không thể không nghĩ rằng nếu một cái gì đó như thế này tồn tại, nó sẽ được tích hợp vào các gói nguyên tử bởi những người thông minh hơn nhiều đang duy trì chúng. (Việc đọc thường xuyên so với viết thường xuyên có thể không phải là một trường hợp cần quan tâm?) Vì vậy, có thể có điều gì đó sai trong suy nghĩ của tôi và một cấu trúc như vậy là không thể?
Tôi đã thấy một số mẫu mã sử dụng 'dễ bay hơi' cho mục đích tương tự, khai thác nó xảy ra trước khi ký hợp đồng. Có một trường đồng bộ hóa riêng, ví dụ:
public Object myRef = new Object();
public volatile int sync = 0;
và tại viết chủ đề / trang web:
myRef = new Object();
sync += 1 //volatile write to emulate barrier
Tôi không chắc chắn điều này hoạt động, và một số tranh luận điều này chỉ hoạt động trên kiến trúc x86. Sau khi đọc các phần liên quan trong JMS, tôi nghĩ rằng nó chỉ được đảm bảo để hoạt động nếu cách viết dễ bay hơi đó được kết hợp với đọc dễ bay hơi từ các luồng cần xem giá trị mới của myRef. (Vì vậy, không thoát khỏi đọc dễ bay hơi).
Trở lại câu hỏi ban đầu của tôi; cái này nó có hoàn toàn có thể xảy ra được không? Có thể có trong Java? Có thể có một trong các API mới trong Java 9 VarHandles không?
sync += 1;
và chủ đề người đọc của bạn đọc sync
giá trị, họ cũng sẽ thấy myRef
cập nhật. Vì cuối cùng bạn chỉ cần người đọc thấy bản cập nhật , nên bạn có thể sử dụng điều này cho lợi thế của mình để chỉ đọc đồng bộ trên mỗi lần lặp thứ 1000 của luồng người đọc hoặc một cái gì đó tương tự. Nhưng bạn cũng có thể thực hiện một mẹo tương tự với volatile
- chỉ cần lưu trữ myRef
trường trong các trình đọc trong 1000 lần lặp, sau đó đọc lại bằng cách sử dụng dễ bay hơi ...
sync
trường, không, độc giả sẽ không chạm vào sync
trường trên mỗi lần lặp, họ sẽ thực hiện nó theo cơ hội, khi họ muốn kiểm tra xem đã có bản cập nhật chưa. Điều đó nói rằng, một giải pháp đơn giản hơn là lưu trữ bộ đệm trong myRef
1000 vòng, sau đó đọc lại ...