Singleton.
别名:单件模式
定义
保证一个类只有一个实例,并提供一个访问该实例的全局节点
应用场景
1.如果程序中的某个类对于所有客户端只有一个可用的实例
单例模式禁止通过除特殊方法以外的任何方式来创建自身的对象。该方法可以创建一个新对象,若该对象已创建,则返回已有的对象
2.需要严格地控制全局变量
单例模式保证类只存在一个实例。除了单例类自己以外,无法通过任何方法替换缓存的实例【可以随时调整限制并设定生成单例实例的数量,只需修改获取实例方法即可】
实现方法
1.在类中添加一个私有静态成员变量用于保存 单例实例
2.声明一个公有静态构建方法用于获取单例实例
3.在静态方法中实现 “ 延迟初始化 ”。该方法会在首次被调用时创建一个新对象,并将其存储在静态成员变量中。此后该方法每次被调用时都返回实例
4.将类的构造函数设为私有。类的静态方法仍能调用构造函数函数,但是其他对象不能调用。
5.检查客户端代码,将对单例的构造函数的调用替换为对其静态构建方法的调用
优缺点
优点:
1.保证一个类只有一个实例
2.获得一个指向该实例的全局访问节点
3.仅在首次请求单例对象时对其进行初始化
缺点:
1.违反了 单一职责原则。
2.可能会掩盖不良设计。eg:程序各组件之间相互了解过多
3.在多线程环境下需要进行特殊处理,避免多个线程多次创建单例对象
结构
UML图
classDiagram
Client-->Singleton
Singleton-->Singleton
class Singleton{
-instance:Singleton
-Singleton()
+getInstance() Singleton
}
参与者
单例 ( Singleton ) :声明一个 getInstance (获取实例)的静态方法 来返回其所属类的一个相同实例。
通用写法
饿汉式
-- 直接在内存中new 实例
静态变量
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
静态代码块
public class Singleton {
private static Singleton instance;
private Singleton(){}
{
instance = new Singleton();
}
public static Singleton getInstance(){
return instance;
}
}
优点:
在类装载时完成实例,避免线程同步问题
缺点:
未达到Lazy Loading的效果
若未使用该实例,则造成内存浪费
懒汉式
-- 只有在get该实例时才new对象
线程不安全
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
优缺点:
拥有Lazy Loading 效果。但仅在单线程下使用
多线程时,易存在if判断未执行时,已有其他线程产生该实例。
线程安全
使用多线程,进行同步方法。
使用同步代码块没有线程同步的作用,因为当进入判断时,容易产生多个实例。
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
优缺点:
解决了线程不安全的问题
但效率太低了。当每个线程都想获取该实例,进入getInstance方法都需要进行同步,而该方法仅需要执行一次便足够了,若后面需要获取该实例们直接return即可。
双重检查
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if (instance == null){
synchronized (Singleton.class){
if (instance == null){
instance = new Singleton();
}
}//synchronized
}
return instance;
}
}
优缺点:
双重检查是多线程开发中常使用的。进行两次判断,保证线程安全。
实例化代码只进行一次,效率提高
静态内部类
静态内部类的特点:
1.进行类加载时,不会对其装载,保证懒加载。
2.调用时,则会去装载该类[ 仅一次 ],保证线程安全。
public class Singleton {
private static Singleton instance;
private Singleton(){}
private static class SingletonInstacne{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonInstacne.INSTANCE;
}
}
枚举
public enum Singleton {
INSTANCE;
public void show(){
System.out.println("Singleton =>" + hashCode());
}
}
借助枚举实现,不仅避免多线程同步问题,还能防止反序列化
容器式
适用于需要大量创建单例对象的场景,便于管理
public class Singleton {
private Singleton(){}
private static Map<String,Object> ioc = new ConcurrentHashMap<>();
private static Object getBean(String className){
synchronized (ioc){
if (!ioc.containsKey(className)){
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className,obj);
}catch (Exception e){
e.printStackTrace();
}
return obj;
}else {
return ioc.get(className);
}
}
}
}