设计模式初级:04-单例模式

1、定义

    创建型模式,提供一种创建对象的方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,并保证只有单个对象被创建,同时提供一个获取该对象的方法。

1.1、条件

  • 单例只能有一个对象。
  • 单例必须自己创建自己的唯一实例。
  • 单例必须给所有其他对象提供这一实例使用。

2、详细介绍

  • 意图:保证一个类仅有一个实例,并提供该类的全局使用方式。
  • 解决的问题:公共的类提供全局使用方式,避免类的频繁创建和销毁。
  • 使用场景:控制对象个数,节省资源消耗。
  • 实现方式:其他对象调用该对象的公共方法时判断对象是否存在,不存在则创建,存在则返回。 
  • 关键代码:默认的构造函数必须私有化,禁止使用者new对象。

3、优缺点

3.1、优点

  • 使用单例模式,内存中只有一个对象,减少内存开销。
  • 避免对文件的重复占用,比如读写文件的时候,只用一个对象对文件进行读或者写。

3.2、缺点

  • 没有接口不能继承,与单一职责冲突。一个类应该只关心内部逻辑,不应该来规范使用者怎么来实例化。

4、应用实例

  • 产生唯一序列号,比如雪花算法生成主键。
  • WEB中的页面计数器,不用每次刷新都在数据库里边记录一次,可以用单例对象先缓存起来。
  • 创建一个全局独享,供系统使用,节约系统资源开销。比如:系统I/O和数据库链接等。

5、实现

5.1、懒汉式单例模式

5.1.1、详细介绍

  • 简介:这种方式时Lazy初始化,就是说使用的时候才回去验证是否创建对象。最主要的是不支持多线程,并发时存在线程安全问题。
  • 线程是否安全:否
  • 是否lazy初始化:是

5.1.2、代码实现

/**
 * Description: 懒汉式单例模式实现
 *  是否lazy初始化: 是
 *  是否线程安全: 否
 *  说明: 这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
 * Created by Administrator
 * Date 2020/1/27 17:18
 */
public class SlobSingle {

    public static SlobSingle slobSingle;

    // 默认构造函数私有化
    private SlobSingle(){}

    public static SlobSingle getInstance(){
        if (null == slobSingle){
            slobSingle = new SlobSingle();
        }
        return slobSingle;
    }
}

5.2、优化后懒汉式单例模式

5.2.1、详细介绍

  • 简介:在获取对象的方法上添加相乘同步锁
  • 是都lazy初始化:是
  • 是否线程安全:是
  • 优点:第一次调用时才创建对象,避免内存浪费
  • 缺点:调用方法加了同步锁,如果频繁使用,对系统性能是很严重的影响。

5.2.2、代码实现

/**
 * Description: 优化懒汉式单例模式实现
 *  是否lazy初始化: 是
 *  是否线程安全: 是
 *  缺点: 性能有消耗
 * Created by Administrator
 * Date 2020/1/27 17:18
 */
public class SlobSingleNew {

    public static SlobSingleNew slobSingle;

    // 默认构造函数私有化
    private SlobSingleNew(){}

    public static synchronized SlobSingleNew getInstance(){
        if (null == slobSingle){
            slobSingle = new SlobSingleNew();
        }
        return slobSingle;
    }
}

5.3、饿汉式单例模式

5.3.1、详细介绍

  • 简介:利用类加载机制,在装载类的时候就对对象进行了初始化。虽然这种方式可以避免线程安全问题,但是容易产生一些垃圾对象,应项系统资源消耗。
  • 是否lazy初始化:否
  • 是否线程安全:是
  • 优点:获取对象的方法没有加锁,执行效率比较高,对性能影响小。
  • 缺点:如果该对象不被使用,可能产生垃圾对象,增加系统资源消耗。

5.3.2、代码实现

/**
 * Description: 饿汉式单例模式
 * Created by Administrator
 * Date 2020/1/27 17:34
 */
public class BadmashSingle {

    private static BadmashSingle badmashSingle = new BadmashSingle();

    private BadmashSingle(){}

    public static BadmashSingle getInstance(){
        return badmashSingle;
    }
}

5.4、双检锁/双重校验锁(DCL,即 double-checked locking)

5.4.1、详细介绍

  • 简介:这种方式采用双锁机制,安全且在多线程情况下能保持高性能。
  • 是否 Lazy 初始化:是
  • 是否多线程安全:是

5.4.2、代码实现

/**
 * Description: 双检锁/双重校验锁(DCL,即 double-checked locking)
 * Created by Administrator
 * Date 2020/1/27 17:43
 */
public class DCLSingle {
    private volatile static DCLSingle single;

    private DCLSingle(){}

    public static DCLSingle getInstance(){
        if (null == single){
            synchronized (DCLSingle.class){
                if (null == single){
                    single = new DCLSingle();
                }
            }
        }
        return single;
    }
}

5.5、登记式/静态内部类

5.5.1、详细介绍

  • 简介:使用静态内部类在类加载的时候将对象的初始化完成,同样利用了类加载器的机制。
  • 是否 Lazy 初始化:是
  • 是否多线程安全:是

5.5.2、代码实现

/**
 * Description: 登记式/静态内部类 单例模式
 * Created by Administrator
 * Date 2020/1/27 17:50
 */
public class StaticClassSingle {
    private static class StaticClassSingleHolder{
        private static final StaticClassSingle single = new StaticClassSingle();
    }

    private StaticClassSingle(){}

    public static final StaticClassSingle getInstance(){
        return StaticClassSingleHolder.single;
    }
}

5.6、枚举式单例模式

5.6.1、详细介绍

  • 简介:应用较少,实现简介,自动支持序列化机制,绝对防止多次实例化。是目前最好的单例模式实现方式。
  • JDK 版本:JDK1.5 起
  • 是否 Lazy 初始化:否
  • 是否多线程安全:是
  • 描述:这种方式是 Effective Java 作者 Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。
  • 缺点:不能通过reflection attack 来调用私有构造方法。

5.6.2、代码实现

/**
 * Description: 枚举式单例模式
 * Created by Administrator
 * Date 2020/1/27 17:58
 */
public enum  EnumSingle {
    INSTANCE;
    public void method() {
    }
}

5.7、几种设计模式使用场景

    一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。

6、更多资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值