美文网首页
图解设计模式之Singleton模式

图解设计模式之Singleton模式

作者: 憨憨二师兄 | 来源:发表于2020-04-06 19:36 被阅读0次

Singleton模式即单例模式,故名思意,单例模式会确保任何情况下都绝对只有一个实例,当我们想在程序中表示某个东西只会存在一个的时候,那么就需要单例模式。

示例程序

Singleton 类

public class Singleton {
    private static Singleton singleton = new Singleton();

    // 构造器是私有的,无法使用new生成实例
    private Singleton() {
        System.out.println("生成了一个实例");
    }

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

Main 类

public class Main {
    public static void main(String[] args){
        Singleton obj1 = Singleton.getInstance();
        Singleton obj2 = Singleton.getInstance();
        if(obj1 == obj2){
            System.out.println("obj1 与 obj2 是相同的实例");
        }else{
            System.out.println("obj1 与 obj2 是不同的实例");
        }
    }
}

运行结果如下:

生成了一个实例
obj1 与 obj2 是相同的实例

Singleton 模式中的角色

Singleton

Singleton模式中只有Singleton这一个角色;Singleton角色中有一个返回实例的static方法,该方法总是会返回同一个实例。

UML

对Singleton模式的思考

单例模式的作用

单例模式的作用其一是为了解决多线程并发访问的问题。
例如:一个系统中可以存在多个预执行任务,但是只能有一个正在工作的任务。例如示例程序:

public class TicketMaker {
    private int ticket = 1000;
    private static TicketMaker ticketMaker = new TicketMaker();
    private TicketMaker(){

    }
    public static TicketMaker getInstance(){
        return ticketMaker;
    }

    public synchronized int getNextTicketNumber(){
        return ticket++;
    }
}

上述程序中,我们只希望生成一个TicketMaker实例,并且能够让getNextTicketNumber在多线程的环境下正常工作,所以我们需要将其定义为synchronized方法。

单例模式的作用其二是为了节约系统的内存,提高系统运行的效率,如果对于一种工具类,你需要频繁调用,如果每次调用都要产生新的实例,那么就会在浪费内存的空间,所以单例模式的一个优点就是减少资源消耗,并且能提高程序的运行速度。

一个问题

有单例模式如下:

public class Singleton1 {
    private static Singleton1 singleton1 = null;
    private Singleton1(){
        
    }
    public static Singleton1 getInstance(){
        if(singleton1 == null){
            singleton1 = new Singleton1();
        }
        return singleton1;
    }
}

为什么上述程序不是严格的Singleton模式 ?
答案:因为在多线程几乎同时调用Singleton.getInstance方法的时候,可能会生成多个实例。
首先将程序改动一下,降低一下处理速度:

public class Singleton1 {
    private static Singleton1 singleton1 = null;
    private Singleton1(){
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){

        }
    }
    public static Singleton1 getInstance(){
        if(singleton1 == null){
            singleton1 = new Singleton1();
        }
        return singleton1;
    }

}

在多线程的环境下,进行程序的测试:

public class Main extends Thread{
    public Main(String name){
        super(name);
    }

    public void run(){
        Singleton1 obj = Singleton1.getInstance();
        System.out.println(getName() + ": obj = " + obj);
    }

    public static void main(String[] args){
        new Main("A").start();
        new Main("B").start();
        new Main("C").start();
    }
}

程序运行的结果为:

C: obj = DesignMode.Singleton.Singleton1@5c13df07
B: obj = DesignMode.Singleton.Singleton1@50564e5e
A: obj = DesignMode.Singleton.Singleton1@5b1a5c4a

可以看到产生了多个不同的实例,为什么会出现这种情况呢?
原因在于,在多线程的环境下,使用如下代码

if(singleton == null){
    singleton = new Singleton();
}

进行判断是线程不安全的,如果在使用singleton == null 判断了第一个实例是否为空后,执行了语句,但是在赋值之前,其他的线程也在进行singleton == null的判断,继而创建出了不同的实例。那么如何修改本程序呢?
修改结果如下:

public synchronized static Singleton1 getInstance(){
        if(singleton1 == null){
            singleton1 = new Singleton1();
        }
        return singleton1;
    }

将getInstance变为 synchronized方法即可。对于这种单例模式:

public class Singleton1 {
    private static Singleton1 singleton1 = null;
    private Singleton1(){
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){

        }
    }
    public synchronized static Singleton1 getInstance(){
        if(singleton1 == null){
            singleton1 = new Singleton1();
        }
        return singleton1;
    }
}

我们称之为懒汉式单例模式,而最开始的那种单例模式则是饿汉式。两者的优缺点为饿汉式为线程安全,调用效率高,但是不能延时加载;懒汉式线程安全,但是因为 getInstance方法为synchronized,所以调用效率不高,但是可以延时加载。其实还有更好的实现单例模式的方法,比如:静态内部类实现单例模式:

public class Singleton2 {
    private static class SingletonClassInstance {
        private static final Singleton2 instance = new Singleton2();
    }

    private Singleton2() {
    }

    public static Singleton2 getInstance() {
        return SingletonClassInstance.instance;
    }
}

这种实现线程安全,调用效率高,并且可以做到延时加载。

相关文章

  • 图解设计模式之Singleton模式

    Singleton模式即单例模式,故名思意,单例模式会确保任何情况下都绝对只有一个实例,当我们想在程序中表示某个东...

  • 图解设计模式Singleton模式

    只生成一个实例的模式被称作单例模式 UML Singleton Main

  • UML

    参考 设计模式之 UML 类图 图解

  • 设计模式分类

    经典23种设计模式: 创建型设计模式: Singleton Pattern(单例模式) PrototypePatt...

  • 前端面试题整理

    1、设计模式 知道什么是singleton, factory, strategy, decrator么? 设计模式...

  • 架构师学习路线图

    内功心法 设计模式 软件设计原则 软件设计模式创建型模式Factory 工厂模式Singleton 单例模式Pro...

  • JAVA设计模式 - 单例模式

    JAVA设计模式 - 单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一...

  • 图解Java设计模式之设计模式面试题

    图解Java设计模式之设计模式面试题 1.1 Java设计模式内容介绍 1.1.1 先看几个经典的面试题 1.1....

  • 设计模式之单体模式 singleton

    什么是单体模式 在面向对象编程中,我们有时候需要只有一个对象或者实例,如注册表,线程池等。俗话说“一山不容二虎”,...

  • 设计模式——单例模式

    设计模式——单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,这种类型...

网友评论

      本文标题:图解设计模式之Singleton模式

      本文链接:https://www.haomeiwen.com/subject/mvibphtx.html