设计模式-单例模式
饿汉式
public final class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
package singleton
type singleton struct {
name string
}
var instance = &singleton{name: "myblog"}
func GetInstance() *singleton {
return instance
}
同步懒汉式
public final class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
package singleton
import "sync"
type singleton struct {
name string
}
var (
once sync.Once
instance *singleton
)
func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{name: "myblog"}
})
return instance
}
[!blue]
- Java:同步创建。
synchronized让判空和创建过程一次只由一个线程执行,避免重复创建实例;实例创建后,每次获取仍会进入同步方法。- Go:只初始化一次。
sync.Once只执行一次初始化函数,其他并发调用会等待它完成,再返回实例。- Go 的注意点:不会自动重试。 初始化函数即使发生 panic,后续
Do调用也不会重新执行它。
双重检查锁(DCL)
public final 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;
}
}
[!blue]
- 锁外判空:减少加锁。 实例已经存在时,直接返回,不再进入同步块。
- 锁内判空:避免重复创建。 当前线程等待锁期间,其他线程可能已经创建实例,所以获得锁后必须再检查一次。
volatile:安全发布实例。 让锁外读取的线程也能看到实例及其已完成的初始化结果,不能省略。此写法适用于 Java 5 及之后的内存模型。
静态内部类
public final class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
}
[!blue]
- 延迟创建。 初始化外部类
Singleton不会初始化Holder;第一次访问Holder.INSTANCE时才创建实例。- 并发安全。 JVM 负责协调
Holder的类初始化,保证初始化完成后其他线程再使用实例,无需手写synchronized或volatile。
枚举
public enum Singleton {
INSTANCE;
public void execute() {
System.out.println("执行任务");
}
}
[!blue]
- 调用方式。 使用
Singleton.INSTANCE.execute(),无需提供getInstance()。- 实例身份。 Java 禁止通过反射调用枚举构造方法;反序列化时也会返回对应的枚举常量,不会创建另一份实例。
- 并发边界。 枚举保证实例身份,但不会自动保护实例中的可变数据;业务方法修改共享状态时,仍需处理并发访问。
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!