Java设计模式(五):单例模式(单件模式或单态模式)

模式动机

对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但只能有一个正在工作的任务。保证一个类只有一个实例对象就是单例模式的动机。一个好的解决方法是,让类负责保存它唯一的实例,这个类可以保证没有其他实例被创建,并且可以提供一个访问该实例的方法。

模式定义

单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局的方法。

单例模式的三大要点:

  • 某个类只能有一个实例
  • 这个类必须自行创建这个实例
  • 该类必须自行向整个系统提供这个实例

模式结构

私有成员变量:Singleton
静态public方法:getInstance()、singletonOperation()
私有构造方法:Singleton(),实例化Singleton类
在这里插入图片描述

时序图

在这里插入图片描述

代码实现

//线程不安全,懒汉单例模式
/**
 * 优点:懒加载启动快,资源占用小,使用时才实例化,无锁。
 * 缺点:非线程安全。
 **/
public class lazySingleton {
    private static lazySingleton singleton=null;

    private lazySingleton(){

    }

    public static lazySingleton getInstance(){
        if(singleton==null){
            singleton=new lazySingleton();
        }
        return singleton;
    }
}


//懒汉式单例,但是线程安全
/**
 *  优点:懒加载启动快,资源占用小,使用时才实例化,有锁。
 *
 *  缺点:synchronized 为独占排他锁,并发性能差。即使在创建成功以后,获取实例仍然是串行化操作。
 *
 **/
public class safeLazySingleton {
    private static safeLazySingleton singleton=null;

    private safeLazySingleton(){

    }

    //加上synchronized,多个线程调用同一个对象的同步方法(synchronized关键字修饰的方法)时会阻塞
    public static synchronized safeLazySingleton getInstance(){
        if(singleton==null){
            singleton=new safeLazySingleton();
        }
        return singleton;
    }
}


/**
 * 懒汉模式--双重加锁检查DCL(Double Check Lock)
 * 优点:懒加载,线程安全。
 *
 **/
public class DCLLazySingleton {

    private static DCLLazySingleton singleton=null;

    private DCLLazySingleton(){

    }

    //加上synchronized锁
    public static synchronized DCLLazySingleton getInstance(){
        if(singleton==null){
            //对DCLLazySingleton类加锁,多个线程实例化该类时会阻塞。
            synchronized(DCLLazySingleton.class){
                if(singleton==null) {
                    singleton = new DCLLazySingleton();
                }
            }

        }
        return singleton;
    }

}


/**
 *
 * 饿汉单例模式
 * 优点:天生是线程安全的,使用时没有延迟。
 * 缺点:启动时即创建实例,启动慢,有可能造成资源浪费。
 **/
public class HungerSingleton {
    private static HungerSingleton singleton=new HungerSingleton();

    private HungerSingleton(){

    }

    public static HungerSingleton getInstance(){
        return singleton;
    }
}


//将懒加载和线程安全完美结合的一种方式(无锁)。(推荐)
/*加载时无需创建初始化私有成员变量(懒加载),在实例化时调用内部静态类,实例化单例对象,天生线程安全
* */
public class HolderSingleton {

    //类的内部静态类,该内部类与外部类的实例没有绑定关系,只有被调用时才会被加载,实现了延迟加载
    private static class SingletonHolder{
        private static HolderSingleton singleton=new HolderSingleton();
    }

    private HolderSingleton(){

    }

    public static  HolderSingleton getInstance(){
        return SingletonHolder.singleton;
     }

}

模式分析

单例模式的目的是保证一个类仅有一个实例,并提供一个访问它的全局访问点。单例模式包含的角色只有一个,就是单例类——Singleton。单例类拥有一个私有构造函数,确保用户无法通过new关键字直接实例化它。除此之外,该模式包含一个静态私有成员变量静态公有的工厂方法。该工厂方法检验实例的存在性并实例化自己,然后存储在静态成员变量中,以确保只有一个实例被创建。

所以,单例模式的实现要注重如下三点:

  • 单例类的构造函数为私有;
  • 提供一个自身的静态私有成员变量;
  • 提供一个公有的静态工厂方法。

模式的优缺点

优点

  • 提供了对唯一实例的受控访问。
  • 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
  • 允许可变数目的实例。基于单例模式进行扩展,可以获得指定数目的对象实例

缺点

  • 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
  • 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
  • 现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失

模式实例

  • 数据库主键编号生成器。数据库只能有一个地方分配下一个主键编号。
  • 操作系统中的打印池,一个系统中只允许运行一个打印池对象

参考

https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/singleton.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值