设为首页 加入收藏

TOP

设计模式 - 单例模式(详解)看看和你理解的是否一样?(一)
2019-10-09 19:59:02 】 浏览:363
Tags:设计模式 单例 模式 详解 看看 理解 是否 一样

一、概述

单例模式是设计模式中相对简单且非常常见的一种设计模式,但是同时也是非常经典的高频面试题,相信还是有很多人在面试时会挂在这里。本篇文章主要针对单例模式做一个回顾,记录单例模式的应用场景、常见写法、针对线程安全进行调试(看得见的线程)以及总结。相信大家看完这篇文章之后,对单例模式有一个非常深刻的认识。

文章中按照常见的单例模式的写法,由浅入深进行讲解记录;以及指出该写法的不足,从而进行演进改造。

秉承废话少说的原则,我们下面快速开始

二、定义

单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

单例模式是创建型模式。

三、应用场景

  1. 生活中的单例:例如,国家主席、公司 CEO、部门经理等。
  2. Java世界中:ServletContextServletContextConfig 等;
  3. Spring 框架应用中:ApplicationContext、数据库的连接池也都是单例形式。

四、常见的单例模式写法

单例模式主要有:饿汉式单例、懒汉式单例(线程不安全型、线程安全型、双重检查锁类型、静态内部类类型)、注册式(登记式)单例(枚举式单例、容器式单例)、ThreadLocal线程单例

下面我们来看看各种模式的写法。

1、饿汉式单例

饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题。

Spring 中 IOC 容器 ApplicationContext 就是典型的饿汉式单例

优缺点

优点:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。

缺点:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能占着茅坑不拉屎。

写法

/**
 * @author eamon.zhang
 * @date 2019-09-30 上午9:26
 */
public class HungrySingleton {
    // 1.私有化构造器
    private HungrySingleton (){}
    // 2.在类的内部创建自行实例
    private static final HungrySingleton instance = new HungrySingleton();
    // 3.提供获取唯一实例的方法(全局访问点)
    public static HungrySingleton getInstance(){
        return instance;
    }
}

还有另外一种写法,利用静态代码块的机制:

/**
 * @author eamon.zhang
 * @date 2019-09-30 上午10:46
 */
public class HungryStaticSingleton {
    // 1. 私有化构造器
    private HungryStaticSingleton(){}

    // 2. 实例变量
    private static final HungryStaticSingleton instance;

    // 3. 在静态代码块中实例化
    static {
        instance = new HungryStaticSingleton();
    }

    // 4. 提供获取实例方法
    public static HungryStaticSingleton getInstance(){
        return instance;
    }
}

测试代码,我们创建 10 个线程(具体线程发令枪 ConcurrentExecutor 在文末源码中获取):

/**
 * @author eamon.zhang
 * @date 2019-09-30 上午11:17
 */
public class HungrySingletonTest {
    @Test
    public void test() {
        try {
            ConcurrentExecutor.execute(() -> {
                HungrySingleton instance = HungrySingleton.getInstance();
                System.out.println(Thread.currentThread().getName() + " : " + instance);
            }, 10, 10);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

测试结果:

pool-1-thread-6 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-1 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-9 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-10 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-2 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-7 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-5 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-3 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-4 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
pool-1-thread-8 : com.eamon.javadesignpatterns.singleton.hungry.HungrySingleton@5e37cce6
...

可以看到,饿汉式每次获取实例都是同一个。

使用场景

这两种写法都非常的简单,也非常好理解,饿汉式适用在单例对象较少的情况。

下面我们来看性能更优的写法——懒汉式单例。


2、懒汉式单例

懒汉式单例的特点是:被外部类调用的时候内部类才会加载。

懒汉式单例可以分为下面这几种写法来。

简单懒汉式(线程不安全)

这是懒汉式单例的简单写法

/**
 * @author eamon.zhang
 * @date 2019-09-30 上午10:55
 */
public class LazySimpleSingleton {
    private LazySimpleSingleton(){}
    private static LazySimpleSingleton instance = null;

    public static LazySi
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇人工智能-智能创意平台架构成长之.. 下一篇结构型设计模式(上)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目