做开发时,有些对象其实只需要一个就够了,比如数据库连接池、配置管理器、日志实例。这时候用单例模式就很合适——保证整个程序运行期间,某个类只存在一个实例。
饿汉式:提前把实例创建好
这种方式在类加载的时候就把实例new出来了,简单直接,线程安全,但可能浪费资源,因为还没用到就已经创建了。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
懒汉式:用的时候再创建
只有调用getInstance()时才创建实例,节省内存。但多线程环境下可能出问题,多个线程同时判断instance为空,就会生成多个实例。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
加锁的懒汉式:线程安全版
加上synchronized关键字,确保同一时间只有一个线程能进入创建逻辑。虽然安全了,但每次调用都得加锁,性能有点拖后腿。
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
双重检查锁定:又安全又高效
只在第一次创建时加锁,后续直接返回实例。既保证线程安全,又避免重复加锁,是实际项目中常用的写法。注意要把instance声明为volatile,防止指令重排序。
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
静态内部类:懒加载 + 线程安全
利用类加载机制保证线程安全。SingletonHolder在外部类加载时不会被初始化,只有调用getInstance()时才会触发,从而实现懒加载。写法简洁,推荐使用。
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
比如你写个App,想让音乐播放器全局只有一个,避免多个声音冲突,用单例就特别合适。选哪种实现方式,得看你的场景:追求简单就用饿汉,讲究性能就上双重检查或静态内部类。