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

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

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


单例模式的定义


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

六种单例的创建方式


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月前
|
设计模式 安全 Java
【设计模式系列笔记】单例模式
单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点,以便全局范围内访问这个实例。单例模式的目标是限制一个类的实例化,确保在整个应用程序中只有一个实例存在,并提供对这个唯一实例的全局访问点。这对于控制对资源的访问、限制特定类的实例数量等场景非常有用。
133 5
|
20天前
|
设计模式 SQL 安全
【设计模式】第二篇:单例模式的几种实现And反射对其的破坏
一个普通实例化,一个反射实例化 但是我们如果通过反射的方式进行实例化类,会有什么问题呢? public static void main(String[] args) throws Exception { Lazy1 lazy1 = getLazy1();
21 5
|
1月前
|
设计模式 安全 Java
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
【JAVA】Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
|
5天前
|
设计模式 安全 Java
Java中的单例模式是一种设计模式,它保证一个类只有一个实例,并提供一个全局访问点
Java单例模式确保类仅有一个实例,并提供全局访问点。常见实现包括: - 饿汉式:静态初始化,线程安全。 - 懒汉式:延迟初始化,需同步保证线程安全。 - 双重检查锁定:优化懒汉式,减少同步开销。 - 静态内部类:延迟加载,线程安全。 - 枚举:简洁线程安全,不适用于复杂构造。 - 容器实现:如Spring框架,用于依赖注入。选择依据需求,如延迟加载、线程安全和扩展性。
36 10
|
5天前
|
设计模式 缓存 安全
Java设计模式的单例模式应用场景
Java设计模式的单例模式应用场景
18 8
|
2天前
|
设计模式 SQL 安全
Java设计模式:单例模式之六种实现方式详解(二)
Java设计模式:单例模式之六种实现方式详解(二)
|
2天前
|
设计模式 JavaScript 前端开发
[JavaScript设计模式]惰性单例模式
[JavaScript设计模式]惰性单例模式
|
5天前
|
设计模式 缓存 安全
java中的设计模式&单例模式
java中的设计模式&单例模式
|
8天前
|
设计模式 安全 Java
Java设计模式之单例模式详解
Java设计模式之单例模式详解
|
1天前
|
设计模式 缓存 安全
【Java设计模式 - 创建型模式1】单例模式
【Java设计模式 - 创建型模式1】单例模式
4 0

热门文章

最新文章