Tôi đã điều tra về hai lần kiểm tra khóa thành ngữ và từ những gì tôi hiểu, mã của bạn có thể dẫn đến các vấn đề về đọc một trường hợp xây dựng một phần TRỪ class Test của bạn là bất di bất dịch:
Các Mô hình bộ nhớ Java cung cấp một sự bảo đảm đặc biệt về sự an toàn khởi tạo để chia sẻ các đối tượng bất biến.
Chúng có thể được truy cập an toàn ngay cả khi đồng bộ hóa không được sử dụng để xuất bản tham chiếu đối tượng.
(Báo giá từ cuốn sách rất nên Java Concurrency in Practice)
Vì vậy, trong trường hợp đó, hai lần kiểm tra khóa thành ngữ sẽ làm việc.Tuy nhiên, nếu trường hợp đó không xảy ra, hãy quan sát rằng bạn đang trả về biến không đồng bộ hóa, vì vậy biến thể hiện có thể không được xây dựng hoàn toàn (bạn sẽ thấy giá trị mặc định của các thuộc tính thay vì các giá trị được cung cấp trong phần tử này). constructor).
Biến boolean không thêm bất kỳ thứ gì để tránh vấn đề, vì nó có thể được đặt thành true trước khi lớp Test được khởi tạo (từ khóa được đồng bộ không tránh sắp xếp lại hoàn toàn, một số sencences có thể thay đổi thứ tự). Không có quy tắc nào xảy ra trước khi trong Mô hình bộ nhớ Java để đảm bảo điều đó.
Và làm cho biến động boolean sẽ không thêm bất cứ điều gì, bởi vì 32 bit biến được tạo ra nguyên tử trong Java. Các thành ngữ khóa kiểm tra đôi sẽ làm việc với họ là tốt.
Vì Java 5, bạn có thể khắc phục sự cố đó tuyên bố biến mẫu là biến động.
Bạn có thể đọc thêm về thành ngữ được chọn đôi trong this very interesting article.
Cuối cùng, một số khuyến nghị Tôi đã đọc:
Cân nhắc nếu bạn nên sử dụng Singleton pattern. Nó được coi là một mô hình chống nhiều người. Dependency Injection được ưu tiên khi có thể. Kiểm tra this.
Hãy cân nhắc kỹ nếu tối ưu hóa khóa đã kiểm tra kép thực sự cần thiết trước khi triển khai, bởi vì trong hầu hết các trường hợp, điều đó sẽ không đáng để thử. Ngoài ra, hãy xem xét việc xây dựng lớp Test trong trường tĩnh, vì việc tải lười chỉ hữu ích khi xây dựng một lớp có rất nhiều tài nguyên và trong hầu hết các lần, nó không phải là trường hợp.
Nếu bạn vẫn cần thực hiện tối ưu hóa này, hãy kiểm tra điều này link cung cấp một số lựa chọn thay thế để đạt được hiệu quả tương tự như những gì bạn đang cố gắng.
Tôi sử dụng nó. Lý do nó hoạt động là vì cá thể sẽ được khởi tạo đầy đủ trước khi dòng khởi tạo = true được nhấn và gán giá trị boolean trong Java là một hoạt động nguyên tử (trên mọi chipset tôi từng sử dụng). – Jono
@Jono Nó phụ thuộc vào trình biên dịch và máy ảo, nếu nó hoạt động hay không. Trình biên dịch có thể tạo ra một bytecode là _caching_ giá trị của '! Initialized' expression, và do đó thiếu nếu một luồng khác thay đổi giá trị của thuộc tính' initialized'. Nếu cùng một mã được chạy song song, khởi tạo thể hiện có thể được thực hiện hai lần. Ngoài ra, trình biên dịch JIT có thể tối ưu hóa biểu thức này từ một bytecode không được tối ưu hóa. Chỉ cần nghĩ rằng: VM phải đánh giá cùng một biểu thức, ngay sau biểu thức kia. Một hoạt động 'dup' ngăn cản việc đánh giá lại, và là một sự chuyển đổi mã hợp lệ theo JLS. – gaborsch