单例模式——java设计模式(七)

简介

单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。

  • 某些类,如id生成器等,只能有一个,需要使用单例模式。
  • 单例模式的要点:一个类只能有一个实例、类必须自行创建这个实例、类必须自行向系统提供这个实例

结构和实现

  • 单例模式只有一个单例类,在内部创建唯一实例,通过静态方法提供这个实例。private的构造方法可以防止单例类在外部被实例化。
  • 单例结构。
    180506.single.png
  • 单例模式实现方式有很多:饿汉式、懒汉式、静态内部类、枚举类。

饿汉式单例

  • 类加载时创建对象,实现简单。
    180506.hungry.png

懒汉式单例

  • 在第一次调用getInstance时实例化,称为延时加载
    180506.lazy.png
  • 可以使用 synchronized加锁方法 或者双重检查锁定来处理多线程问题。
    • synchronized锁定对getInstance静态方法的调用,确保只有一个线程调用方法,但是每次调用该方法均要进行线程锁定判断,性能较低。
    • 双重检查的原因:某一瞬间线程A和B均通过的第一重判断,A进入锁定的代码块,创建实例结束后,B进入锁定的代码块,需要第二重判断防止B再次创建实例。
    • volatile关键字强制线程从主内存中取变量,而不是线程的本地内存,这样对该变量的改变线程之间是可见的。但是这也会屏蔽一些JVM的优化。volatile关键字原理

静态内部类单例

  • 饿汉式单例一开始就会消耗系统的资源,懒汉式单例线程控制复杂、性能受限。
  • 可以使用静态内部类储存创建的单例,第一次调用getInstance方法的时候加载内部类HolderClass,初始化其中的静态变量instance。线程安全性由JVM保证,确保instance只被初始化一次。
    180506.static.png
  • 静态内部类可以实现延迟加载、保证线程安全、不影响性能,但是受编程语言限制,某些语言不支持。

枚举单例

  • 使用enum类型储存单例,类似静态内部类,编程更加简单,可以实现延迟加载、保证线程安全、不影响性能,但是受编程语言限制
    180506.enum.png

实例

  • 开发负载均衡软件,将并发访问的数据分发到多个服务器上进行处理。由于服务器需要动态增减,并且用户的请求需要统一分发,为了避免分配冲突问题,需要确保负载均衡器的唯一性。
    180506.loadbalancer.png

优缺点和适用范围

  • 优点:
    • 控制唯一实例的访问
    • 节约资源。系统只存在一个该类的实例,对于需要频繁创建和销毁的类,可以提高性能。
    • 控制类的数目。扩展单例模式,使一个类拥有指定数量的实例。
  • 缺点:
    • 无抽象层。扩展困难。
    • 单例类职责过重。提供创建方法和业务方法,违反单一职责原则。
    • 可能被回收。在提供自动垃圾回收的环境中,如果对象长时间不使用,会被回收,从而丢失对象的状态。
  • 适用环境:
    • 系统只需要一个实例。如业务需要或者资源消耗太大。
    • 调用只允许使用一个访问点。

jdk中的应用

  • java.lang.Runtime,封装了运行时环境,饿汉式单例。
public class Runtime {
    private static Runtime currentRuntime = new Runtime();
    private Runtime() {}
    public static Runtime getRuntime() {
        return currentRuntime;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_40369829/article/details/80216819