Đây được gọi là hiệu ứng "xuất bản sớm".
Đặt đơn giản, JVM được phép sắp xếp lại hướng dẫn chương trình (vì lý do hiệu suất), nếu sắp xếp lại không vi phạm các hạn chế của JMM.
Bạn mong đợi mã f = new FinalFieldExample();
để chạy như:
1. tạo ra các thể hiện của FinalFieldExample
2. assign 3 đến x
3. assign 4 đến y
4. assign tạo đối tượng để biến f
Nhưng trong mã được cung cấp, không có gì có thể ngăn chặn JVM từ hướng dẫn sắp xếp lại, vì vậy nó có thể chạy các mã như:
1. tạo ra các thể hiện của FinalFieldExample
2. assign 3 đến x
3. gán thô, không được khởi tạo đầy đủ đối tượng để biến f
4. assign 4 đến y
Nếu sắp xếp lại xảy ra trong một đơn môi trường chủ đề, chúng tôi thậm chí sẽ không nhận thấy nó. Đó là bởi vì chúng ta mong đợi, các đối tượng đó sẽ được tạo ra hoàn toàn trước khi chúng ta bắt đầu làm việc với chúng và JVM tôn trọng những mong đợi của chúng ta. Bây giờ, những gì có thể xảy ra, nếu một số chủ đề chạy mã này cùng một lúc? Trong ví dụ tiếp theo thread1 đang thực hiện phương pháp writer()
và thread2 - Phương pháp reader()
:
Chủ đề 1: tạo ra các thể hiện của FinalFieldExample
Chủ đề 1: Sử dụng từ 3 đến x
Chủ đề 1: gán liệu, đối tượng khởi tạo không đầy đủ để biến f
chủ đề 2: đọc f
, nó không phải là null
chủ đề 2: đọc fx, nó được 3
chủ đề 2: đọc fy, nó vẫn là 0
chủ đề 1: Sử dụng 4 đến y
Chắc chắn là không tốt. Để ngăn JVM làm điều này, chúng ta cần cung cấp thêm thông tin về chương trình. Đối với ví dụ cụ thể này, có một số cách để khắc phục tính nhất quán của bộ nhớ:
- khai báo
y
là final
biến. Điều này sẽ gây ra hiệu ứng "freeze". Tóm lại, các biến cuối cùng sẽ luôn được khởi tạo vào thời điểm bạn truy cập chúng, nếu tham chiếu đến đối tượng không bị rò rỉ trong khi xây dựng.
- khai báo
f
là volatile
biến.Thao tác này sẽ tạo "synchronization order" và khắc phục sự cố. Nói tóm lại, các hướng dẫn không thể được sắp xếp lại dưới dạng ghi dễ bay hơi và đọc ở trên dễ bay hơi. Gán cho biến số f
là một ghi dễ bay hơi, có nghĩa là không thể sắp xếp lại và thực thi các lệnh sau khi gán. Đọc từ biến số f
là đọc dễ đọc, vì vậy, không thể thực thi đọc f.x
trước khi đọc. Sự kết hợp của v-write và v-read được gọi là thứ tự đồng bộ hóa và cung cấp độ nhất quán bộ nhớ mong muốn.
Here là một blog hay, có thể trả lời tất cả câu hỏi của bạn về JMM.
Tôi biết điều này liên quan đến JVM được phép sắp xếp lại các bài viết, nhưng tôi không biết chi tiết. : - | –
Khi tôi nghĩ rằng bạn chưa đọc jsr133 đúng cách, điều đó được đề cập rõ ràng ở đó.'Không viết một tham chiếu đến đối tượng đang được xây dựng ở một nơi khác có thể thấy chủ đề trước khi hàm tạo của đối tượng kết thúc. Nếu điều này được theo sau, khi đối tượng được xem bởi một chuỗi khác, chuỗi đó sẽ luôn thấy phiên bản được tạo đúng của trường cuối cùng của đối tượng' nhưng đối với chuỗi trường không cuối cùng có thể thấy giá trị mặc định. – Prashant
vâng, điều này thật điên rồ. hy vọng họ sẽ sửa nó trong java9. – ZhongYu