单例模式是指保证一个类在全局只有一个实例,并且提供一个全局可以访问的入口
为什么需要单例模式
- 节省内存、节省计算
很多情况下,我们只需要一个实例就够了,如果出现了很多实例,反而属于浪费
- 为了保证结果的正确
- 方便管理,很多工具类只需要一个实例
单例模式的应用场景
无状态的工具类
- 日志工具
- 字符串工具
全局信息类
- 全局计数
- 环境变量
单例模式常见的写法
单例模式看似简单,但其实同时反映了并发、类加载、序列化等重要知识点的掌握程度和水平
单例模式有很多种写法:
- 饿汉式
- 懒汉式
- 静态内部类式
- 双重检查式
- 枚举式
饿汉式
优点:在类装载的同时就完成了实例化,避免了线程同步的问题
缺点:在类装载的时候完成实例化,没有达到懒加载的效果
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
静态代码块形式
public class Singleton {
private static Singleton singleton;
static {
singleton = new Singleton();
}
private Singleton(){}
public Singleton getInstance(){
return singleton;
}
}
懒汉式
只能在单线程下使用
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
线程安全的懒汉式
线程安全,但是效率太低
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
这种写法有问题,会发生线程安全问题
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
if(singleton == null){
synchronized (Singleton.class) {
singleton = new Singleton();
}
}
return singleton;
}
}
线程安全的双重检查模式
优点:线程安全、延迟加载
public class Singleton {
// 加 volatile 关键字原因:
// 新建实例不是原子操作,防止发生指令重排序,拿到未完成初始化的对象
private static volatile Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
// 去掉它,所有线程都变成串行执行
if (singleton == null) {
synchronized (Singleton.class) {
// 去掉它,会发生线程安全问题
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
静态内部类形式
public class Singleton {
private Singleton() {}
private static class SingletonInstance {
private static final Singleton singleton = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstance.singleton;
}
}
双重锁和静态内部类写法都能保证线程安全并且延迟加载,但是不能防止被反序列化生成多个实例
枚举写法
public class Singleton {
private Singleton() {}
public static Singleton getInstance() {
return SingletonEnum.INSTANCE.getInstance();
}
// 枚举是线程安全的,并且JVM保证只会装载一次
private enum SingletonEnum {
INSTANCE;
private final Singleton instance;
SingletonEnum() {
instance = new Singleton();
}
private Singleton getInstance() {
return instance;
}
}
}
1 条评论
555