Singleton giới hạn class chỉ có đúng 1 instance trong app, cung cấp điểm truy cập toàn cục. Dùng cho: logger, config, DB connection pool, cache.
Các cách implement, từ đơn giản đến tốt nhất:
1. Eager — đơn giản, thread-safe nhờ JVM. Nhược: tạo cả khi không dùng.
private static final Logger INSTANCE = new Logger();
public static Logger getInstance() { return INSTANCE; }**2.
Bill Pugh — initialization-on-demand holder (khuyến nghị):**
private static class Holder { static final Logger INSTANCE = new Logger(); }
public static Logger getInstance() { return Holder.INSTANCE; }Lazy thật sự + thread-safe nhờ JVM + không sync overhead.
3. Enum singleton (tốt nhất theo Effective Java):
public enum Logger { INSTANCE; public void log(String m) {} }
Logger.INSTANCE.log("hi");Chống reflection + serialization attack mặc định. Nhược: không lazy.
Nhược điểm của Singleton:
- Khó test: global state, khó mock — cần mockStatic (chậm).
- Hidden dependency: getInstance() không khai báo phụ thuộc.
- Tight coupling vào concrete class.
2026: dùng DI container (Spring) — bean ngầm singleton scope trong container, vẫn truyền qua constructor injection nên test mock được. Đừng tự viết Singleton trừ khi không có lựa chọn.
Singleton restricts a class to exactly one instance with a global access point. Common for: loggers, config, DB pools, caches.
Implementations, simple → best:
1. Eager — simple, thread-safe via JVM. Downside: created even when unused.
private static final Logger INSTANCE = new Logger();
public static Logger getInstance() { return INSTANCE; }**2.
Bill Pugh — initialization-on-demand holder (recommended):**
private static class Holder { static final Logger INSTANCE = new Logger(); }
public static Logger getInstance() { return Holder.INSTANCE; }Truly lazy + thread-safe via JVM + no sync overhead.
3. Enum singleton (best per Effective Java):
public enum Logger { INSTANCE; public void log(String m) {} }
Logger.INSTANCE.log("hi");Defends against reflection + serialization attacks. Downside: not lazy.
Drawbacks:
- Hard to test: global state, hard to mock — needs mockStatic (slow).
- Hidden dependencies: getInstance() does not declare its dependency.
- Tight coupling to a concrete class.
2026: use a DI container (Spring) — beans default to singleton scope but flow through constructor injection so tests can mock. Do not roll your own Singleton unless you must.