单例模式

模式动机

单例模式(Singleton Pattern)是结构最简单的设计模式,它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以确保系统中一个类只有一个实例,且该实例易于被外界访问,从而方便对实例个数的控制并节约系统资源。


  1. 定义一个全局变量可以确保对象随时都可以被访问,但是不能防止实例化多个对象。(代码实现)
  2. 更好的办法是让类自身负责创建和保存它的唯一实例,并保证不能创建其他实例,并且提供一个访问该实例的方法。(机制实现)

模式定义

  • 单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
  • 单例模式的要点有三个:
    • 某个类只能有一个实例
    • 必须自行创建这个实例
    • 必须自行向整个系统提供这个实例
  • 单例模式是一种对象创建型模式

模式结构

image

模式分析


  • 私有构造函数
  • 静态私有成员变量(自身类型)
  • 静态公有的工厂方法

单例类:

public class Singleton {
    //静态私有成员变量
    private static Singleton instance=null;
        //私有构造函数
    private Singleton() {
    }
       //静态公有工厂方法,返回唯一实例
    public static Singleton getInstance() {
        if(instance==null)
            instance=new Singleton();
        return instance;
    }
}

  • 单例模式的目的

    • 保证一个类只有一个唯一的实例,并为它提供一个全局访问点。
  • 实现单例模式的思想

    • 为了防止客户端程序使用构造函数来创建多个对象,可以将构造函数声明为私有的,这样客户端程序就不可以使用它来创建任何对象。
  • 单例模式的问题

    • 如果声明构造函数为私有类型,那么没有客户端程序可以使用它来创建任何对象,因此它对客户端程序是无用的。
  • 单例模式优点

    • 提供了对唯一实例的受控访问
    • 可以节约系统资源,提高系统的性能
    • 允许可变数目的实例(多例类)
  • 单例模式缺点

    • 扩展困难(缺少抽象层)
    • 单例类的职责过重。单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心它是否是单例的,是不是要单例取决于环境,单例模式把“要单例”和业务逻辑融合在一个类中
    • 由于自动垃圾回收机制,可能会导致共享的单例对象的状态丢失
  • 在以下情况下可以使用单例模式

    • 系统只需要一个实例对象,或者因为资源消耗太大而只允许创建一个对象
    • 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例

饿汉式(Eager Singleton):顾名思义,该模式在类被加载时就会实例化一个对象。

public class EagerSingleton {
    private static final EagerSingleton instance = new EagerSingleton(); 
    private EagerSingleton() { }
    public static EagerSingleton getInstance() {
        return instance;
    }
}

懒汉式(Lazy Singlenton):该模式只在你需要对象时才会生成单例对象(比如调用getInstance方法)

public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() { }

public static LazySingleton getInstance() {
	if (instance == null) {
		instance = new LazySingleton();
    }
	return instance;
}
}

关于Synchronized 类型的方法

  • Synchronized类型的方法限制每个执行此方法的线程必须在执行下一个线程之前完全执行;
  • 通过这种方式,创建的对象在多个线程的情况下是唯一的;
  • 也就是说,我们已经给Synchronized类型的对象添加了锁。当一个线程执行此方法时,其他方法无法接管。其他线程应该等待.
  • 只有在当前线程执行完该方法后,另一个线程才能开始执行该方法
锁方法:
public class LazySingleton {
private static LazySingleton instance = null;
private LazySingleton() { }
synchronized public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
        }
return instance;
}
}
锁代码段
public static LazySingleton getInstance() { 
    if (instance == null) {
        synchronized (LazySingleton.class) {
            instance = new LazySingleton();
        }
    }
    return instance;
}

懒汉式与饿汉式比较

懒汉式 饿汉式
实例化 外部调用时 类加载时
线程安全 不安全 安全
执行效率 较低 较高
内存 不浪费 浪费
作者:|街酒|,原文链接: https://www.cnblogs.com/sorrymine/p/17384211.html

文章推荐

Java 网络编程 —— 非阻塞式编程

单例模式(Singleton Pattern)

聊一聊redis十种数据类型及底层原理

深度学习之PyTorch实战(5)——对CrossEntropyLoss损失函数的...

从源码解析Go exec timeout 实现机制

前端安全问题——暴破登录

了解CSS Module作用域隔离原理

day50-正则表达式01

聊聊OOP中的设计原则以及访问者模式

MySQL中读页缓冲区buffer pool

面试突击51:为什么单例一定要加 volatile?

理解RESTful Api设计