
Singleton trong Java là gì?
Singleton là một trong những mẫu thiết kế cấp lớp đơn giản nhất. Đôi khi người ta nói "lớp này là singleton", có nghĩa là lớp này triển khai mẫu thiết kế singleton. Đôi khi, cần phải viết một lớp trong đó chúng ta hạn chế việc khởi tạo đối với một đối tượng. Ví dụ: một lớp chịu trách nhiệm ghi nhật ký hoặc kết nối với một đối tượng duy nhất. cơ sở dữ liệu. Mẫu thiết kế singleton mô tả cách chúng ta có thể đạt được điều này. Singleton là một mẫu thiết kế thực hiện hai việc:-
Nó đảm bảo rằng sẽ chỉ có một thể hiện của lớp.
-
Nó cung cấp một điểm truy cập toàn cầu duy nhất cho trường hợp đó.
-
Một nhà xây dựng tư nhân. Điều này hạn chế khả năng tạo các đối tượng của lớp bên ngoài chính lớp đó.
-
Một phương thức tĩnh công khai trả về thể hiện của lớp. Phương pháp này được gọi là getInstance . Đây là điểm truy cập toàn cầu đối với thể hiện của lớp.
Tùy chọn thực hiện
Mẫu thiết kế singleton được áp dụng theo nhiều cách khác nhau. Mỗi lựa chọn đều tốt và xấu theo cách riêng của nó. Như mọi khi, không có lựa chọn hoàn hảo nào ở đây, nhưng chúng ta nên cố gắng đạt được một lựa chọn. Trước hết, hãy quyết định điều gì tạo nên điều tốt và điều xấu, và những chỉ số nào ảnh hưởng đến cách chúng ta đánh giá các triển khai khác nhau của mẫu thiết kế. Hãy bắt đầu với những điều tốt đẹp. Dưới đây là các yếu tố làm cho việc triển khai trở nên hấp dẫn và hấp dẫn hơn:-
Khởi tạo chậm: thể hiện không được tạo cho đến khi cần thiết.
-
Mã đơn giản và minh bạch: số liệu này, tất nhiên, là chủ quan, nhưng nó quan trọng.
-
An toàn luồng: hoạt động chính xác trong môi trường đa luồng.
-
Hiệu suất cao trong môi trường đa luồng: ít hoặc không chặn luồng khi chia sẻ tài nguyên.
-
Không khởi tạo lười biếng: khi lớp được tải khi ứng dụng bắt đầu, bất kể có cần thiết hay không (nghịch lý thay, trong thế giới CNTT, tốt hơn là nên lười biếng)
-
Mã phức tạp và khó đọc. Số liệu này cũng mang tính chủ quan. Nếu mắt bạn bắt đầu chảy máu, chúng tôi sẽ cho rằng việc triển khai không phải là tốt nhất.
-
Thiếu an toàn chủ đề. Nói cách khác, "luồng nguy hiểm". Hoạt động không chính xác trong môi trường đa luồng.
-
Hiệu suất kém trong môi trường đa luồng: các luồng chặn lẫn nhau mọi lúc hoặc thường xuyên khi chia sẻ tài nguyên.
Mã số
Bây giờ chúng ta đã sẵn sàng xem xét các tùy chọn triển khai khác nhau và chỉ ra những ưu và nhược điểm:Đơn giản
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
}
Việc thực hiện đơn giản nhất. Ưu điểm:
-
Mã đơn giản và minh bạch
-
Chỉ an toàn
-
Hiệu suất cao trong môi trường đa luồng
- Không khởi tạo lười biếng.
Khởi tạo lười biếng
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {}
public static Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Ưu điểm:
-
Khởi tạo lười biếng.
-
Chủ đề không an toàn
Truy cập được đồng bộ hóa
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
}
Ưu điểm:
-
Khởi tạo lười biếng.
-
Chỉ an toàn
-
Hiệu suất đa luồng kém
Kiểm tra khóa hai lần
public class Singleton {
private static final Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
Ưu điểm:
-
Khởi tạo lười biếng.
-
Chỉ an toàn
-
Hiệu suất cao trong môi trường đa luồng
-
Không được hỗ trợ trong các phiên bản Java trước đó dưới 1.5 (việc sử dụng từ khóa dễ bay hơi đã được sửa kể từ phiên bản 1.5)
chủ lớp
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
public static final Singleton HOLDER_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.HOLDER_INSTANCE;
}
}
Ưu điểm:
-
Khởi tạo lười biếng.
-
Chủ đề an toàn.
-
Hiệu suất cao trong môi trường đa luồng.
-
Hoạt động chính xác yêu cầu đảm bảo rằng đối tượng đơn lẻ được khởi tạo mà không có lỗi. Mặt khác, lệnh gọi đầu tiên đến phương thức getInstance sẽ dẫn đến ExceptionInInitializerError và tất cả các lệnh gọi tiếp theo sẽ tạo ra NoClassDefFoundError .
Thực hiện | Khởi tạo lười biếng | Chỉ an toàn | hiệu suất đa luồng | Khi nào thì sử dụng? |
---|---|---|---|---|
Đơn giản | - | + | Nhanh | Không bao giờ. Hoặc có thể khi khởi tạo lười biếng không quan trọng. Nhưng không bao giờ sẽ tốt hơn. |
Khởi tạo lười biếng | + | - | không áp dụng | Luôn luôn khi không cần đa luồng |
Truy cập được đồng bộ hóa | + | + | Chậm | Không bao giờ. Hoặc có thể khi hiệu suất đa luồng không thành vấn đề. Nhưng không bao giờ sẽ tốt hơn. |
Kiểm tra khóa hai lần | + | + | Nhanh | Trong một số trường hợp hiếm hoi khi bạn cần xử lý các ngoại lệ khi tạo singleton (khi singleton của chủ sở hữu lớp không được áp dụng) |
chủ lớp | + | + | Nhanh | Bất cứ khi nào cần xử lý đa luồng và có sự đảm bảo rằng đối tượng singleton sẽ được tạo mà không gặp sự cố. |
Ưu và nhược điểm của mẫu đơn
Nói chung, một singleton thực hiện chính xác những gì được mong đợi ở nó:-
Nó đảm bảo rằng sẽ chỉ có một thể hiện của lớp.
-
Nó cung cấp một điểm truy cập toàn cầu duy nhất cho trường hợp đó.
-
Một singleton vi phạm nguyên tắc trách nhiệm duy nhất: ngoài các nhiệm vụ trực tiếp của nó, lớp singleton còn kiểm soát số lượng các phiên bản.
-
Sự phụ thuộc của một lớp bình thường vào một singleton không được hiển thị trong hợp đồng công khai của lớp.
-
Các biến toàn cầu là xấu. Cuối cùng, một singleton biến thành một biến toàn cầu khổng lồ.
-
Sự hiện diện của một singleton làm giảm khả năng kiểm tra của ứng dụng nói chung và các lớp sử dụng singleton nói riêng.
GO TO FULL VERSION