单例模式(创建型模式)

创建型概述

  • 创建型模式关注"怎么创建对象",特点是"将对象的创建和使用分离",降低系统的耦合度

创建型模式分为:

  • 单例模式
  • 工厂方法模式
  • 抽象工程模式
  • 原型模式
  • 建造者模式

单例模式

  • 该模式只有一个类,并确保只创建一个对象,提供唯一访问对象的方式,可以直接访问,不需要实例化该类对象。

角色

  • 单例类: 只能创建一个实例的类
  • 访问类:使用单例类

举例

单例设计模式分两类:

  1. 饿汉式:类加载时创建实例对象 方式1:静态成员变量
/**
 * @author :yangzhipeng
 * @date : 2023/3/6 14:27
 * Description : 单例模式:饿汉式 :静态成员变量
 */

public class Singleton {
    /**
     * 私有构造方法 确保只有一个对象
     */
    private Singleton(){}
    /**
     * 在本类中创建本类对象
     */
    private static Singleton instance = new Singleton();

    /**
     * 提供一个公共的访问方式,让外界获取该对象
     */
    public static Singleton getInstance(){
        return instance;
    }

}
  1. 方式2:静态代码块
    /**
     * 声明Singleton类型的变量
     */
    private static Singleton instance;

    /**
     * 在静态代码快中进行赋值
     */
    static{
        instance = new Singleton();
    }
    

懒汉式:首次使用该对象时创建对象
方式1:(线程不安全)

/**
 * @author :yangzhipeng
 * @date : 2023/3/6 14:27
 * Description : 单例模式:懒汉式1 :线程不安全
 */

public class Singleton {
    /**
     * 私有构造方法 确保只有一个对象
     */
    private Singleton(){}
    /**
     * 声明类型
     */
    private static Singleton instance;

    /**
     * 提供一个公共的访问方式,让外界获取该对象
     */
    public static Singleton getInstance(){
        //判断instance是否为null
        //若没有,创建一个 ; 若有,直接返回
        if(instance == null){
            //线程1等待,线程2执行到这里也会创建
            instance = new Singleton();
        }
        return instance;
    }

}

线程安全解决办法:方法上加synchronize同步锁

	/**
     * 提供一个公共的访问方式,让外界获取该对象
     */
    public static synchronized Singleton getInstance(){
        //判断instance是否为null
        //若没有,创建一个 ; 若有,直接返回
        if(instance == null){
            //线程1等待,线程2执行到这里也会创建
            instance = new Singleton();
        }
        return instance;
    }

方式3:双重检查锁:调整加锁的时机 (推荐使用)

/**
 * @author :yangzhipeng
 * @date : 2023/3/6 14:27
 * Description : 单例模式:懒汉式2 :双重检查锁
 */

public class Singleton {
    /**
     * 私有构造方法 确保只有一个对象
     */
    private Singleton(){}
    /**
     * 声明类型
     */
    private static Singleton instance;

    /**
     * 提供一个公共的访问方式,让外界获取该对象
     * synchronized加锁 使其线程安全
     */
    public static  Singleton getInstance(){
        //判断instance是否为null
        //若没有,创建一个 ; 若有,直接返回
        if(instance == null){
            //抢到锁之后再次判断是否为空
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

方法4:静态内部类
JVM在加载外部类的过程中,不会加载静态内部类,内部类的属性/方法被调用时才会加载。被static修饰属性可以保证只实例化一次,并严格保证实例化顺序。

/**
 * @author :yangzhipeng
 * @date : 2023/3/6 14:27
 * Description : 单例模式:懒汉式2 :静态内部类方式
 */

public class Singleton {
    /**
     * 私有构造方法 确保只有一个对象
     */
    private Singleton(){}
    /**
     * 静态方法创建对象
     */
    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    /**
     * 对外提供静态方法获取该对象
     */
    public static  Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

静态内部类方式在没有加任何锁的情况下保证了多线程下的安全,并且没有性能影响和空间浪费。比较推荐

极力推荐:饿汉式:枚举方式

/**
 * @author :yangzhipeng
 * @date : 2023/3/6 14:27
 * Description : 单例模式:饿汉式 :枚举方式
 */

public enum Singleton {
    INSTANCE;
}

枚举类型是线程安全的,只会装载一次,是所有单例实现中唯一一种不会被破坏的单例实现模式

存在的问题:
1.破坏单例模式(除了枚举方式)

问题的解决:

  • 序列化,反序列化方式破坏单例模式解决方法:
    在Singleton类中添加readResolve()方法
/**
 * @author :yangzhipeng
 * @date : 2023/3/6 14:27
 * Description : 单例模式:懒汉式2 :静态内部类方式
 */

public class Singleton {
    /**
     * 私有构造方法 确保只有一个对象
     */
    private Singleton(){}
    /**
     * 静态方法创建对象
     */
    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    /**
     * 对外提供静态方法获取该对象
     */
    public static  Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }

    /**
     * 当进行反序列化时,会自动调用该方法,将该方法的返回值直接返回
     */
    public Object readResolve(){
        return SingletonHolder.INSTANCE;
    }
}
  • 反射方式破解单例的解决方式
    在Singleton中添加静态变量判断是否是第一次创建对象
public class Singleton {

    //解决反射破解单例
    private static boolean flag = false;

    /**
     * 私有构造方法 确保只有一个对象
     */
    private Singleton(){
        //加锁解决多线程
        synchronized (Singleton.class){
            //flag值为false说明是第一次访问,反之直接抛出异常
            if(flag){
                throw new RuntimeException("不能创建多个Singleton对象");
            }
            //将flag设置为true
            flag = true;
        }
    }
    /**
     * 静态方法创建对象
     */
    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    /**
     * 对外提供静态方法获取该对象
     */
    public static  Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值