欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > 单例模式(Singleton Pattern)

单例模式(Singleton Pattern)

2024/11/30 6:32:32 来源:https://blog.csdn.net/yuiezt/article/details/140313950  浏览:    关键词:单例模式(Singleton Pattern)

单例模式(Singleton Pattern)

定义

是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

隐藏起所有的构造方法。

属于创建型模式。


适用场景

确保任何情况下都绝对只有一个实例。
比如数据库连接池、配置文件读取、缓存等。


标准示例

在这里插入图片描述

1. 饿汉式单例

在单例类首次加载时,就创建实例。

  • 优点:执行效率高,性能高,没有锁
  • 缺点:某些情况下,可能会有内存浪费(系统中单例类很多的时候,无论是否使用,加载时都会初始化到内存)
public class HungrySingleton {//静态成员变量private static final HungrySingleton INSTANCE;//代码块对成员变量赋初始值static {INSTANCE = new HungrySingleton();}//私有的构造函数private HungrySingleton(){}//全局访问方法public static HungrySingleton getInstance(){return INSTANCE;}
}

2. 懒汉式单例

被外部类调用时才会创建实例。

  • 优点:节省了内存
  • 缺点:线程不安全问题
public class LazySingleton {private static LazySingleton instance;private LazySingleton(){}public static LazySingleton getInstance(){if(instance == null){// 位置Ainstance = new LazySingleton();// 位置B}// 位置Creturn instance;}
}

上述代码的线程不安全体现在两种情况:

两个线程输出实例相同,实际上是后者覆盖了前者:
有两个线程,都执行到了位置B,这时后者会覆盖掉前者,当线程继续到位置C时,它们输出的确是同一个实例——把前者覆盖掉的那个实例。

两个线程同时进入非空判断条件中,然后按顺序返回,输出两个不同实例:
有两个线程,一个执行到了位置A,另一个执行到了位置B,然后位置B的线程执行到位置C,输出它的实例;位置A的也随后执行到位置B,创建了新的实例覆盖原有实例,然后执行到位置C输出该新实例。两次输出的是不同的实例

解决懒汉式单例线程安全问题的方法一:加锁

public class LazySingleton {private static LazySingleton instance;private LazySingleton(){}//加锁解决线程安全问题public synchronized static LazySingleton getInstance(){if(instance == null){instance = new LazySingleton();}return instance;}
}

但是,这种方式会有副作用,所有的获取实例的调用,都会受到synchronized的性能影响。

解决懒汉式单例线程安全问题的方法二:双重检查

public class DoubleCheckLazySingleton {//加 volatile 是为了解决指令重排序的问题,保证instanc变量先创建private volatile static DoubleCheckLazySingleton instance;private DoubleCheckLazySingleton(){}public static DoubleCheckLazySingleton getInstance(){//第一次检查,目的是要判断是否要加锁if(instance == null){synchronized (DoubleCheckLazySingleton.class){//第二次检查,目的是判断是否要创建实例if(instance == null) {instance = new DoubleCheckLazySingleton();}}}return instance;}
}

上述代码可以解决问题,只是可读性不够高。

解决懒汉式单例线程安全问题的方法三:静态内部类
利用原理:内部类只有在调用时才会被加载。

public class StaticInnerClassLazySingleton {private StaticInnerClassLazySingleton(){}public static StaticInnerClassLazySingleton getInstance(){return LazyInnerClass.INSTANCE;}private static class LazyInnerClass{private static final StaticInnerClassLazySingleton INSTANCE = new StaticInnerClassLazySingleton();}
}

3. 注册式单例

将每一个实例都缓存到统一的容器中,使用唯一标识获取实例

public class ContainerSingleton {private ContainerSingleton(){}private static ContainerSingleton instance;private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>();public static Object getInstance(String className){Object instance = null;if(!ioc.containsKey(className)){try {instance = Class.forName(className).newInstance();ioc.put(className,instance);} catch (Exception e) {e.printStackTrace();}return  instance;}else{return ioc.get(className);}}
}

以上就是 单例模式 的全部内容,感谢阅读。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com