23种设计模式入门 -- 单例模式

单例模式:采用一定的方法,使得软件运行中,对于某个类只能存在一个实例对象,并且该类只能提供一个取得实例的方法。

分类

  • 饿汉式

    1. 静态常量方式

    2. 静态代码块方式

  • 懒汉式

    1. 普通方式,线程不安全

    2. 同步方法方式,线程安全

    3. 同步代码块方式,线程不安全

  • 其他方式

    1. 双重检查

    2. 静态内部类

    3. 枚举

实现思路:

  1. 想要实现单例,即不能让外部随意的去实例化对象。所以需要构造器私有

  2. 既然不允许外部去创建了,所以需要在类的内部创建对象

  3. 外部需要使用对象,所以需要对外提供一个获取实例的方法

一、饿汉式

根据对象创建的时机,可以分为饿汉式和懒汉式。饿汉式,即在类加载的时候立即创建实例,根据所学知识我们可以很快想到要使用static关键字将属性和类相关联。以下提供两种书写方式供参考。

特点

  • 优点:写法简单,在类装载的时候就完成实例化,避免了线程同步问题

  • 缺点:在类装载的时候就完成了实例化,如果开始至终都没有使用这个实例,会造成内存浪费

1.静态常量方式

class Singleton01{
    //构造器私有,防止外部new
    private Singleton01(){

    }
    //内部创建对象
    private final static Singleton01 instance = new Singleton01();

    //提供给外部创建实例的静态方法
    public static Singleton01 getInstance(){
        return instance;
    }

}

2.静态代码块方式

class Singleton02{
    //构造器私有,防止外部new
    private Singleton02(){

    }
    //内部创建对象
    private static Singleton02 instance;
    static {
        instance = new Singleton02();
    }

    //提供给外部创建实例的静态方法
    public static Singleton02 getInstance(){
        return instance;
    }

}

这种方式和静态常量的实现方式逻辑和优缺点是一样的,只是写法不同。

二、懒汉式

懒汉式,即在类加载时并不实例化对象,等到使用对象实例的时候才去实例化,也被称为懒加载效果。这样做的好处可以节约资源,减少浪费,只有需要的时候采取创建,不需要就不会实例化。

1.普通方式(线程不安全)

class Singleton01{
    // 构造器私有
    private Singleton01(){

    }
    // 定义静态变量,实例化留在获取实例的getInstance方法,起到懒加载效果
    private static Singleton01 instance;

    public static Singleton01 getInstance(){
        // 判断如果为空才创建,起到懒加载
        if (instance == null){
            instance = new Singleton01();
        }

        return instance;
    }
}

问题:在多线程情况下,假设类还未第一次实例化,此时两个进程同时执行到了if(instance==null),而未来得及往下执行时,此时两者校验都成立,都会执行实例化操作,将有可能出现创建多个实例的问题。

2.同步方法方式(线程安全)

既然存在线程安全问题,肯定会想到使用synchronized关键字来解决

class Singleton02{
    private static Singleton02 instance;

    private Singleton02(){

    }
    //使用synchronized关键字来实现线程安全
    public static synchronized Singleton02 getInstance(){
        if (instance == null){
            instance = new Singleton02();
        }
        return instance;
    }
}

这样的方式可以起到线程安全的效果,但是每个线程都需要等待锁,所以又会存在效率低的问题,于是有人想到了将锁的范围缩小到方法的内部,使用同步代码块的方式

3.同步代码块方式(线程不安全)

这样的方式好不好呢?先看代码

class Singleton03{
    private static Singleton03 instance;

    private Singleton03(){

    }

    public static Singleton03 getInstance(){
        if (instance == null){
            // 这里的synchronized其实没有实际意义,可能会产生多个实例
            synchronized (Singleton03.class){
                instance = new Singleton03();
            }
        }
        return instance;
    }
}

这样锁的范围是变小了,但是还会存在多个线程同时判断到if (instance == null),即使在后面加上锁,依旧会在后续创建实例,只是延迟了一点而已,所以这种写法不可取

三、其他方式

1.双重检查

为了能够实现懒加载的效果,同时兼顾效率,于是出现了这种写法

class Singleton01{
    //volatile,当有发生变化时即时储存到内存中。防止指令重排
    private static volatile Singleton01 instance;

    private Singleton01(){

    }

    //双重检查,解决线程同步问题,又保证效率
    public static Singleton01 getInstance(){
        if (instance == null){ // 第一次检查,降低产生锁的概率
            synchronized (Singleton01.class){
                if(instance == null){ // 第二次检查,保证线程安全
                    instance = new Singleton01();
                }
            }
        }
        return instance;
    }
}

使用双重检查,第一次检查提升效率,第二次检查保证线程安全,简直美滋滋

2.静态内部类

利用静态内部类在被调用时才会加载,即存在懒加载效果,所以也可以这样写

class Singleton02{
    private Singleton02(){

    }

    /*
        静态内部类在外部类装载的时候不会马上执行,起到懒加载作用。
        类的静态属性只有在第一次使用的时候才会加载,JVM在类加载时是线程安全的
     */
    private static class SingletonInstance{
        private static final Singleton02 INSTANCE = new Singleton02();
    }

    public static Singleton02 getInstance(){
        return SingletonInstance.INSTANCE;
    }

}

3.枚举

枚举方式是最简单的写法,也是被很多人推崇的写法

enum Singleton03{
    INSTANCE;
}

简单明了...

四、小结

使用单例模式,可以使一个类只存在一个实例对象,从而节省了系统资源。

上文中列出了8个写法,其中懒加载的写法存在线程安全和效率的问题,需要谨慎使用。比较推荐的写法有5种:懒加载2种+其他方式3种。当认定单例的对象在软件中一定会用到,可以使用懒加载,反之可以使用其他方式

(0)

相关推荐

  • 面试高频-吃透单例设计模式

    单例设计模式 单例设计模式的介绍 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法(静态方法). 比如 Hiber ...

  • 单例模式的八种写法

    单例模式作为日常开发中最常用的设计模式之一,是最基础的设计模式,也是最需要熟练掌握的设计模式.单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点.那么你知道单例模式有多少种实现方式 ...

  • 设计模式笔记(一):Singleton 设计模式

    今天开始学习设计模式,借此机会学习并整理学习笔记. 设计模式是一门不区分语言的课程,什么样的编程语言都可以用到设计模式.如果说java语法规则比作武功招式的话,那么设计模式就是心法. 设计模式共有23 ...

  • 图解Java设计模式之单例设计模式

    图解Java设计模式之单例设计模式 设计模式介绍 设计模式类型 单例设计模式介绍 饿汉式(静态常量) 饿汉式(静态代码块) 懒汉式(线程不安全) 懒汉式(线程安全,同步方法) 懒汉式(线程安全,同步代 ...

  • 设计模式:单例模式 (关于饿汉式和懒汉式)

    定义 单例模式是比较常见的一种设计模式,目的是保证一个类只能有一个实例,而且自行实例化并向整个系统提供这个实例,避免频繁创建对象,节约内存. 单例模式的应用场景很多, 比如我们电脑的操作系统的回收站就 ...

  • 设计模式-创建型-单例模式

    前言: 单例模式,顾名思义,只存在一个实例.官方定义:对于类的单例模式设计,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法). ...

  • java常见设计模式之---单例模式

    java常见设计模式之---单例模式 1.单例模式简介 应用场景举例 2.单例模式的特点 3.单例模式和静态类 4.单例模式的经典实现 饿汉式单例(典型实现) 饿汉式-静态代码块 懒汉式单例创建,五种 ...

  • 大话设计模式笔记(十八)の单例模式

    单例模式 定义 保证一个类仅有一个实例,并提供一个访问它的全局访问点. 通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象.一个最好的办法就是,让类自身负责保存它的唯一实例.这 ...

  • Java设计模式之单例模式

    单例模式,是特别常见的一种设计模式,因此我们有必要对它的概念和几种常见的写法非常了解,而且这也是面试中常问的知识点. 所谓单例模式,就是所有的请求都用一个对象来处理,如我们常用的Spring默认就是单 ...

  • 23种设计模式入门 - 设计模式概述及七大原则

    设计模式的目的 使程序拥有更好的的 代码复用性(一次编译,处处运行[手动狗头]) 可读性(不可替代性堪忧呀) 可扩展性(新增功能时方便) 可靠性(新增功能后对旧功能没有影响) 高内聚,低耦合 设计模式 ...

  • 有点污,23 种设计模式的通俗解释

    有点污,23 种设计模式的通俗解释

  • 23种设计模式全解析

    一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...

  • 如何学习23种设计模式及其思想?

    感觉设计模式是看着简单 ,但是一用就不会,23种设计模式,学的人头大,相信大家都是这样的 设计模式在程序员的面试中会被考到,通常是介绍其原理并说出优缺点.或者对比几个比较相似的模式的异同点.在笔试中可 ...

  • 面向对象23种设计模式系列(一)- 创建型设计模式

    本章是面向对象23种设计模式系列开篇,首先我们来看下什么是设计模式? 面向对象23种设计模式: 1.面向对象语言开发过程中,遇到的种种场景和问题,提出了解决方案和思路,沉淀下来就变成了设计模式. 2. ...

  • 23种设计模式之原型模式

    原型模式 1.基本介绍 1)原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并通过拷贝这些原型,创建新的对象. 2)原型模式是一种创建型设计模式,允许一个对象再创建另一个可定制的 ...

  • 【资料】23种设计模式和六大设计原则

    程序IT圈 www.cxyquan.com 优秀的程序猿技术公众号 1 设计模式的六大原则 ☛开闭原则 对扩展开放,对修改关闭.在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果.简 ...

  • 设计模式系列之一:23种GoF设计模式概述

    23种GoF设计模式概述 在前面,我们对 GoF 的 23 种设计模式进行了分类,这里先对各个设计模式的功能进行简要介绍,以便有个大概了解.后面的章节再进行详细介绍. 创建型模式 关注于怎么创建对象的 ...

  • 设计模式系列之二:23种GoF设计模式的分类

    GoF设计模式一共有23个.一般可以按目的和作用范围来进行划分,具体划分方法如下:第一,这些模式按目的(即完成什么样任务)来划分为创建型.结构型和行为型这三种模式:创建型:用来创建对象.单例.原型.抽 ...