写点什么

JMM 应用实例:单例模式

用户头像
朱华
关注
发布于: 2020 年 10 月 26 日

单例模式的 8 种写法(这里仅给出 4 种):

  1. 饿汉式

  2. 双重检查

  3. 静态内部类

  4. 枚举


什么是单例模式?

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。


单例模式适用的场景

  1. 无状态的工具类:

比如日志工具类,不管是在哪里使用,我们需要的只是它帮我们记录日志信息,除此之外,并不需要在它的实例对象上存储任何状态,这时候我们就只需要一个实例对象即可。

  1. 全局信息类:

比如我们在一个类上记录网站的访问次数,我们不希望有的访问被记录在对象 A 上,有的却记录在对象 B 上,这时候我们就让这个类成为单例。


饿汉式

public class Singleton {
private final static Singleton INSTANCE = new Singleton();
private Singleton() { } public static Singleton getInstance() { return INSTANCE; }}
复制代码


双重检查


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


  • 优点:线程安全;延迟加载;效率高

  • 为什么要使用 double-check?

  1. 线程安全

  2. 单 check 可不可以?

单 check 也是可以的,但是要考虑到性能问题

  • 为什么要使用 volatile

我们要了解,对象的创建并不是原子性的,对象的创建需要 3 个步骤:

  1. 新建一个空的对象

  2. 调用构造方法

  3. 返回对象

因为创建对象不是原子的,那么就有可能发生步骤 3 发生在步骤 2 之前,就会出现空指针的异常(属性引用时为空,但事实上它需要被赋值)。这恰恰是因为发生了重排序导致的。而使用 volatile 就避免了重排序的发生。


静态内部类


public class Singleton {
private Singleton() { }
private static class SingletonInstance { private final static Singleton INSTANCE = new Singleton(); }
public static Singleton getInstance() { return SingletonInstance.INSTANCE; }}
复制代码


枚举

public enum Singleton {		INSTANCE;}
复制代码
  • 写法简单

  • 线程安全有保障

通过反编译后代码我们可以看到,public final class T extends Enum,说明,该类是继承了 Enum 类的,同时 final 关键字告诉我们,这个类也是不能被继承的。同时类中的属性和方法都是 static 的。我们知道当一个 Java 类第一次被真正使用到的时候静态资源被初始化、Java 类的加载和初始化过程都是线程安全的。所以,创建一个 enum 类型是线程安全的


  • 避免反序列化破坏单例


用户头像

朱华

关注

见自己,见天地,见众生。 2018.08.07 加入

还未添加个人简介

评论

发布
暂无评论
JMM 应用实例:单例模式