想象你是一家奶茶店唯一的收银机:
1. 所有员工必须用同一台收银机结账
2. 避免出现多台收银机导致账目混乱
3. 需要时直接使用,无需每次重新安装
这就是单例模式的核心:**确保一个类只有一个实例,并提供全局访问点**。
一、单例模式四大金刚(实现方式)
#### 1. 🍔 饿汉式(静态变量)
```java
// 就像早餐店提前做好的包子
public class singleton {
private static singleton instance = new singleton(); // 类加载就创建
private singleton() {} // 锁死构造函数
public static singleton getInstance() {
return instance; // 直接享用现成的
}
}
```
- ✅ 优点:简单粗暴线程安全
- ❌ 缺点:可能造成资源浪费(不用也创建)
#### 2. 🍜 懒汉式(双重检查锁)
```java
// 像现点现做的拉面师傅
public class demo2 {
private static volatile demo2 instance; // volatile防指令重排
private demo2() {}
public static demo2 getInstance() {
if(instance == null) { // 第一次检查:避免不必要的锁
synchronized(demo2.class) { // 加锁制作
if(instance == null) { // 第二次检查:防穿透
instance = new demo2();
}
}
}
return instance; // 热腾腾的拉面出锅
}
}
```
- ✅ 优点:延迟加载+线程安全+高性能
- ⚠️ 注意:必须加 `volatile` 防止指令重排序
#### 3. 🧩 静态内部类(完美方案)
```java
// 像智能外卖柜,需要时才取餐
public class demo1 {
private demo1() {}
private static class Holder { // 外卖柜
static final demo1 INSTANCE = new demo1();
}
public static demo1 getInstance() {
return Holder.INSTANCE; // 开柜取餐
}
}
```
- ✅ 优点:懒加载+线程安全+无锁高性能
- 💡 原理:JVM保证类加载的线程安全性
#### 4. 👑 枚举式(终极防御)
```java
// 像银行金库,绝对安全
public enum BankVault {
INSTANCE; // 天生单例
public void operation() { /* 业务方法 */ }
}
```
- ✅ 优点:防反射+防序列化破坏
- 🏆《Effective Java》推荐的首选方式
---
### 二、实战运用场景
1. **配置管理器**(全局唯一配置)
```java
public class ConfigLoader {
private static ConfigLoader instance;
private Properties config;
private ConfigLoader() {
loadConfig(); // 加载配置文件
}
public static ConfigLoader getInstance() {
if(instance == null) {
synchronized(ConfigLoader.class) {
if(instance == null) instance = new ConfigLoader();
}
}
return instance;
}
public String getConfig(String key) {
return config.getProperty(key);
}
}
```
2. **数据库连接池**(共享连接资源)
```java
public class ConnectionPool {
private static final ConnectionPool INSTANCE = new ConnectionPool();
private List<Connection> connections = new ArrayList<>();
private ConnectionPool() {
initializePool(); // 初始化连接池
}
public static ConnectionPool getInstance() {
return INSTANCE;
}
public Connection getConnection() { /* ... */ }
}
```
3. **日志记录器**(统一日志输出)
```java
public enum Logger {
INSTANCE;
public void log(String message) {
System.out.println("[LOG] " + LocalDateTime.now() + ": " + message);
}
}
// 使用
Logger.INSTANCE.log("用户登录成功");
```
---
### 三、避坑指南(注意事项)
1. **序列化破坏防御**(添加readResolve方法)
```java
// 在静态内部类实现中
private Object readResolve() {
return Holder.INSTANCE; // 告诉序列化机制返回已有实例
}
```
2. **反射攻击防御**(构造器加固)
```java
private demo() {
if(instance != null) { // 双重检查锁实现中
throw new IllegalStateException("单例已存在!");
}
}
```
3. **多线程环境**:
- 饿汉式/枚举式天生线程安全
- 懒汉式务必使用双重检查锁
- 避免在getInstance()方法上加synchronized(性能杀手)
4. **类加载器问题**:
- 在OSGi等复杂类加载环境下
- 使用上下文类加载器确保唯一性
---
### 四、各实现方式性能对比
| 实现方式 | 线程安全 | 延迟加载 | 防反射 | 防序列化 | 性能 |
|----------------|----------|----------|--------|----------|------|
| 饿汉式 | ✅ | ❌ | ❌ | ❌ | ⭐⭐⭐⭐ |
| 同步方法懒汉式 | ✅ | ✅ | ❌ | ❌ | ⭐ |
| 双重检查锁 | ✅ | ✅ | ❌ | ❌ | ⭐⭐⭐ |
| 静态内部类 | ✅ | ✅ | ❌ | ❌ | ⭐⭐⭐⭐|
| **枚举式** | ✅ | ❌ | ✅ | ✅ | ⭐⭐⭐⭐|
> 💡 实际选择建议:优先选择枚举式,需要延迟加载时用静态内部类
---
### 五、最佳实践总结
1. **简单场景**:直接使用枚举式(最安全简洁)
```java
public enum ServiceManager {
INSTANCE;
public void service() { /* ... */ }
}
```
2. **延迟加载场景**:静态内部类(平衡性能与安全)
```java
public class LazyService {
private LazyService() {}
private static class Holder {
static final LazyService INSTANCE = new LazyService();
}
public static LazyService getInstance() {
return Holder.INSTANCE;
}
}
```
3. **防御性编程**:
```java
// 防止克隆破坏
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
```
> 🌟 **黄金法则**:
> 如果你的单例需要处理资源(文件/网络连接),优先考虑枚举或饿汉式;
> 如果是重量级对象需要懒加载,用静态内部类;
> 在框架开发中务必防御反射和序列化攻击!
单例模式就像公司唯一的CEO,确保全局决策统一。正确使用能让你的系统更健壮,滥用则会导致代码僵化——关键是根据场景找到平衡点!
创作者模式—单例设计模式
风语者日志2025-09-27 9:06