「干货分享」经典设计模式之单例模式

简介: 「干货分享」经典设计模式之单例模式

设计模式千千万,总是单例最常见。


单例模式的定义


保证一个类仅有一个实例,并提供一个访问它的全局访问点。

六种单例的创建方式


1.饿汉式

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

优点:

基于类的加载机制,避免了多线程同步问题,加载速度快。

缺点:

在类加载的时候就完成初始化,没有懒加载,如果没有使用这个实例,会造成内存浪费。


2.懒汉式-线程不安全版

public class Singleton {
  private static Singleton instance;
  private Singleton() {}
  public static Singleton getInstance() {
    if(instance == null){
      instance = new Singleton();
    }
    return instance;
  }
}

优点:

第一次调用是才初始化对象,避免浪费资源

缺点:

加载速度慢,线程不安全


3.懒汉式-线程安全版(synchronized加锁)

public class Singleton {
  private static Singleton instance;
  private Singleton() {}
  public static synchronized Singleton getInstance() {
    if(instance == null){
      instance = new Singleton();
    }
    return instance;
  }
}

优点:

多线程中保证线程安全

缺点:

每次获取对象实例,都需要进行同步,造成不必要的同步开销。

4.双重校验锁


public class Singleton {
  private static volatile Singleton instance;
  private Singleton() {}
  public static Singleton getInstance() {
    if(instance == null){
      synchronized(Singleton.class) {
        if(instance == null) {
          instance = new Singleton();
        }
      }
    }
    return instance;
  }
}

优点:

线程安全,懒加载,减少同步开销

缺点:

第一个获取对象速度稍慢,但其在某些情况下也会出现失效的情况,并不是完美的方式。

这里面使用了两次判空:第一次为了不必要的加锁同步,第二次是确保在instance为null的情况下才创建实例,避免多次创建。

方法中还是用了关键字volatile对变量进行修饰,有如下几个作用:

1.在Java内存模型中volatile可以保证可见性,及防止程序指令重排序。

2.对象的创建分为如下几个步骤:

instance = new Singleton();
  • 1.为instance分配内存空间
  • 2.初始化instance
  • 3.将instance指向内存地址

如果不加volatile的话,程序的执行顺序就可能变成1->3->2,多线程中就会导致线程获取一个没有初始化的实例。例如线程a 执行了1,3, 此时线程b调用getInstance()发现instance不为空,返回instance,但此时instance还未初始化。


5.静态内部类


public class Singleton {
  private Singleton() {}
  public static Singleton getInstance() {
    return SingletonHolder.sInstance;
  } 
  private static class SingletonHolder {
    private static final Singleton sInstance = new Singleton();
  }
}

第一次加载类的时候不会初始化instance,只有第一次调用getInstance()的时候才会进行加载SingleHolder并初始化instance,保证线程安全,也能保证实例唯一,推荐使用这种方式。


6.枚举


public enum Singleton {
INSTANCE;
public void doSomeThing(){}
}

默认枚举单例的创建是线程安全的,并且任何情况下都是单例。

以上就是6中常见的单例创建形式,按需使用吧。

单例的使用场景


  • 整个项目需要一个共享访问点或者数据
  • 创建一个对象需要耗费的资源太多,比如访问数据库资源等
  • 工具类对象
目录
相关文章
|
1月前
|
设计模式 存储 SQL
PHP中的设计模式:单例模式的探索
在PHP开发中,单例模式是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。本文将通过一个简单的例子,逐步引导你理解如何在PHP中实现和利用单例模式,以及它在实际项目中的应用价值。
|
3月前
|
设计模式 缓存 安全
Java设计模式的单例模式应用场景
Java设计模式的单例模式应用场景
43 4
|
3月前
|
设计模式 SQL 安全
【设计模式】第二篇:单例模式的几种实现And反射对其的破坏
一个普通实例化,一个反射实例化 但是我们如果通过反射的方式进行实例化类,会有什么问题呢? public static void main(String[] args) throws Exception { Lazy1 lazy1 = getLazy1();
29 5
|
1月前
|
设计模式 存储 负载均衡
【五】设计模式~~~创建型模式~~~单例模式(Java)
文章详细介绍了单例模式(Singleton Pattern),这是一种确保一个类只有一个实例,并提供全局访问点的设计模式。文中通过Windows任务管理器的例子阐述了单例模式的动机,解释了如何通过私有构造函数、静态私有成员变量和公有静态方法实现单例模式。接着,通过负载均衡器的案例展示了单例模式的应用,并讨论了单例模式的优点、缺点以及适用场景。最后,文章还探讨了饿汉式和懒汉式单例的实现方式及其比较。
【五】设计模式~~~创建型模式~~~单例模式(Java)
|
1月前
|
设计模式 安全 程序员
C#设计模式之单例模式
C#设计模式之单例模式
40 3
|
30天前
|
设计模式 SQL 缓存
Java编程中的设计模式:单例模式的深入理解与应用
【8月更文挑战第22天】 在Java的世界里,设计模式是构建可维护、可扩展和灵活的软件系统的基石。本文将深入浅出地探讨单例模式这一经典设计模式,揭示其背后的哲学思想,并通过实例演示如何在Java项目中有效运用。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇洞悉软件设计深层逻辑的大门。
26 0
|
1月前
|
设计模式 存储 数据库连接
Python设计模式:巧用元类创建单例模式!
Python设计模式:巧用元类创建单例模式!
32 0
|
1月前
|
设计模式 安全 测试技术
[设计模式]创建型模式-单例模式
[设计模式]创建型模式-单例模式
|
2月前
|
设计模式 安全 C++
C++一分钟之-C++中的设计模式:单例模式
【7月更文挑战第13天】单例模式确保类只有一个实例,提供全局访问。C++中的实现涉及线程安全和生命周期管理。基础实现使用静态成员,但在多线程环境下可能导致多个实例。为解决此问题,采用双重检查锁定和`std::mutex`保证安全。使用`std::unique_ptr`管理生命周期,防止析构异常和内存泄漏。理解和正确应用单例模式能提升软件的效率与可维护性。
32 2
|
2月前
|
设计模式 安全 Java
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
Java面试题:设计模式如单例模式、工厂模式、观察者模式等在多线程环境下线程安全问题,Java内存模型定义了线程如何与内存交互,包括原子性、可见性、有序性,并发框架提供了更高层次的并发任务处理能力
60 1