Tôi không nghĩ rằng có ai đó đã thực sự trả lời câu hỏi , vì vậy tôi sẽ thử.
Cái dễ bay hơi và cái đầu tiên if (instance == null)
là không "cần thiết". Khóa sẽ làm cho mã này an toàn.
Vì vậy, câu hỏi là: tại sao bạn lại thêm cái đầu tiên if (instance == null)
?
Lý do có lẽ là để tránh thực thi đoạn mã bị khóa một cách không cần thiết. Trong khi bạn đang thực thi mã bên trong khóa, bất kỳ luồng nào khác cố gắng thực thi mã đó cũng bị chặn, điều này sẽ làm chậm chương trình của bạn nếu bạn cố gắng truy cập singleton thường xuyên từ nhiều luồng. Tùy thuộc vào ngôn ngữ / nền tảng, cũng có thể có chi phí phát sinh từ chính khóa mà bạn muốn tránh.
Vì vậy, kiểm tra null đầu tiên được thêm vào như một cách thực sự nhanh chóng để xem bạn có cần khóa hay không. Nếu bạn không cần tạo singleton, bạn có thể tránh khóa hoàn toàn.
Nhưng bạn không thể kiểm tra xem tham chiếu có là null hay không mà không khóa nó theo một cách nào đó, vì do bộ nhớ đệm của bộ xử lý, một luồng khác có thể thay đổi nó và bạn sẽ đọc một giá trị "cũ" dẫn đến việc bạn phải nhập khóa một cách không cần thiết. Nhưng bạn đang cố gắng tránh một ổ khóa!
Vì vậy, bạn làm cho singleton dễ bay hơi để đảm bảo rằng bạn đọc giá trị mới nhất mà không cần sử dụng khóa.
Bạn vẫn cần khóa bên trong bởi vì biến số dễ bay hơi chỉ bảo vệ bạn trong một lần truy cập duy nhất vào biến - bạn không thể kiểm tra và thiết lập nó một cách an toàn mà không sử dụng khóa.
Bây giờ, điều này thực sự hữu ích?
Tôi sẽ nói "trong hầu hết các trường hợp, không".
Nếu Singleton.Instance có thể gây ra sự kém hiệu quả do các ổ khóa, thì tại sao bạn lại gọi nó thường xuyên đến mức đây sẽ là một vấn đề nghiêm trọng ? Toàn bộ điểm của một singleton là chỉ có một, vì vậy mã của bạn có thể đọc và lưu vào bộ nhớ cache tham chiếu singleton một lần.
Trường hợp duy nhất tôi có thể nghĩ về nơi mà bộ nhớ đệm này sẽ không thể thực hiện được khi bạn có một số lượng lớn các luồng (ví dụ: một máy chủ sử dụng một luồng mới để xử lý mọi yêu cầu có thể tạo ra hàng triệu luồng chạy rất ngắn, mỗi luồng mà sẽ phải gọi Singleton.Instance một lần).
Vì vậy, tôi nghi ngờ rằng khóa kiểm tra hai lần là một cơ chế có vị trí thực sự trong các trường hợp quan trọng về hiệu suất rất cụ thể, và sau đó mọi người đã tranh luận về nhóm "đây là cách thích hợp để làm điều đó" mà không thực sự nghĩ nó làm gì và liệu nó có sẽ thực sự cần thiết trong trường hợp họ đang sử dụng nó.