美文网首页Java设计模式
设计模式--单例模式

设计模式--单例模式

作者: 快点学 | 来源:发表于2020-01-04 21:33 被阅读0次

确保一个类只有一个实例,并提供全局访问点。

  • 懒汉式 - 线程不安全
  • 饿汉式 - 线程安全
  • 懒汉式 - 线程安全
  • 双重校验所 - 线程安全

至于为什么会有懒汉、饿汉这样的名字,我也不明白...

首先说下为什么需要单例模式?


简单来说有些场景下我们并不希望也不需要某个类同时出现多个实例,比如:当前用户的实例。当用户登录了某个APP后,我们并不只是验证完用户名和密码就完事了,还希望能够记录用户的状态,例如用户收藏或点赞了某个动态,这些信息会被同步到服务器,用户也能在“我的收藏”、“我的点赞”中看到自己的新增的记录。这种情况如果能够始终保存当前用户信息是很有用的,系统能够根据当前用户的ID十分方便的去同步当前用户在云端的各种表。

一、单线程基本形式(懒汉式-线程不安全)

public class Singleton {
    private static Singleton uniqueInstance;

(1) private Singleton () { }

(2) public static Singleton getInstance () {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

(1)处将构造方法设为private,表明只有该类自己可以访问,在类外无法去实例化。
(2)处采用静态方法,使得类外可以使用Singleton.getInstance()来获取该类的实例化对象。同样静态方法对应的静态变量保证了该变量能够长期存活。

上述代码在单线程环境下能够很好的运行,但是在多线程环境下则会出问题:

if (uniqueInstance == null) {
    uniqueInstance = new Singleton();
}

当多个线程同时获取实例且实例还为null的时候,可能会多次进入该语句实例化该实例,违反了一个类只有一个实例的原则。

为了避免出现这样的问题,有多种实现方法:

二、直接实例化(饿汉式-线程安全)

public class Singleton {
    private static Singleton uniqueInstance = new Singleton();

    private Singleton() { }

    public static Singleton getInstance() {
        return uniqueInstance;
    }

直接实例化直接避免了是否已经实例化的判断,但是没有了延迟实例化的好处,过早地实例化增加了不必要的开销。

三、改成同步方法(懒汉式-线程安全)

public class Singleton {
    private static Singleton uniqueInstance;

    private Singleton () { }

    public static synchronized Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
    }
}

同步方法迫使每个线程在进入这个方法之前,要先等侯别的线程离开该方法。但是这样的做法会引入严重的性能问题:只在第一次实例化的时候这个同步机制才发挥了作用,在以后的获取实例时反倒影响了各个线程对实例的使用,多了不必要的等待

四、双重检查锁 - 线程安全

public class Singleton {
    private volatile static Singleton uniqueInstance;

    private Singleton() { }

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

使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行

判断两次uniqueInstance == null的原因是因为可能多个线程都在uniqueInstance == null的情况下进入了条件语句,如果在里面不再判断一次的话,对实例化语句的同步就没有起到作用,只是延缓了后一个线程的执行。

参考资料

  • 《Head First设计模式》
  • CSNOTE

相关文章

  • 单例模式Java篇

    单例设计模式- 饿汉式 单例设计模式 - 懒汉式 单例设计模式 - 懒汉式 - 多线程并发 单例设计模式 - 懒汉...

  • python中OOP的单例

    目录 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 单例

    目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计模式 是 前人...

  • 设计模式 - 单例模式

    设计模式 - 单例模式 什么是单例模式 单例模式属于创建型模式,是设计模式中比较简单的模式。在单例模式中,单一的类...

  • 设计模式

    常用的设计模式有,单例设计模式、观察者设计模式、工厂设计模式、装饰设计模式、代理设计模式,模板设计模式等等。 单例...

  • 2018-04-08php实战设计模式

    一、单例模式 单例模式是最经典的设计模式之一,到底什么是单例?单例模式适用场景是什么?单例模式如何设计?php中单...

  • python 单例

    仅用学习参考 目标 单例设计模式 __new__ 方法 Python 中的单例 01. 单例设计模式 设计模式设计...

  • 基础设计模式:单例模式+工厂模式+注册树模式

    基础设计模式:单例模式+工厂模式+注册树模式 单例模式: 通过提供自身共享实例的访问,单例设计模式用于限制特定对象...

  • 单例模式

    JAVA设计模式之单例模式 十种常用的设计模式 概念: java中单例模式是一种常见的设计模式,单例模式的写法...

  • 设计模式之单例模式

    单例设计模式全解析 在学习设计模式时,单例设计模式应该是学习的第一个设计模式,单例设计模式也是“公认”最简单的设计...

网友评论

    本文标题:设计模式--单例模式

    本文链接:https://www.haomeiwen.com/subject/daufactx.html