美文网首页
“单例模式”

“单例模式”

作者: 落雨松 | 来源:发表于2019-01-18 14:34 被阅读0次

瞎述

作为java工程师,设计模式相当于一个礼仪文化,善于利用礼仪文化的人,无论从哪方面讲都是让人觉得安逸。

--------------------设计模式主要分为:创建型、结构型、行为型-----------

(一)所谓创建型,就包括:
“单例”、“简单工厂”、“工厂方法”、“抽象工厂”、“生成器”、“原型”

(二)所谓行为型,就包括:
“责任链”、“命令”、“解释器”、“迭代器”、“中介者”、“备忘录”、“观察者”、“状态”、“策略”、“模板方法”、“访问者”、“空对象”

(三)所谓结构型,就包括:
“适配器”、“桥接”、“组合”、“装饰”、“外观”、“享元”、“代理”

一、单例模式

一般情况下,单例模式中都有:
1、一个私有静态变量放实例变量
2、一个私有构造函数
3、一个公有静态实例对象返回方法getInstance()

单例模式具有延迟加载、公用一个实例对象,节约资源,提高性能的特点。

① 首先介绍第一种 “懒汉式---线程不安全” 的单例模式(甚至都不能被称为单例)
解释都在代码注释里:

public class Singleton {
    //一个私有静态变量:类加载时载入
    private static Singleton singleton;
    //一个私有构造函数
    private Singleton(){}
    //一个公有静态方法:用来返回创建的实例
    public static  Singleton getInstance(){
        /*
            这里只有lazy1 == null ,如果多个线程同时进入,
            多个线程的都没有被实例化,那么将会导致实例化多个对象
            造成线程不安全
         */
        if(singleton == null){
            singleton = new Singleton();
        }
        return singleton;
    }
}

②于是出现了第二种:“饿汉式--线程安全”
只是将静态私有实例变量直接实例化,如:

    private static Singleton singleton = new Singleton();

很显然这样并没有起到单例模式节约资源的作用(我每次getInatance都会重新实例化一个对象,还不如不写这个“单例模式”)

③继续改善,出现“懒汉式---线程安全”的单例模式
依旧采用“懒汉式”,也就是说依旧只是判断了 singleton == null ,只不过这里在getInstace方法上加了一个同步锁,如代码:

 public static synchronized Singleton getInstance(){

这样做的好处可以是不同线程获取同一个实例对象,但是缺点也显而易见,那就是当多个线程竞争获取这个实例对象时候,会造成阻塞,你想要这个对象,我也想要。所以这种设计很容易导致性能问题。

④ 然后,然后就是“双重校验锁---线程安全”

通过对getInstace方法内部的实例化那一个部分,通过同步代码块的方法,在同步代码块外层和内层都加上之前的singleton == null,双重判断,使得线程安全,同时也尽可能的避免了锁占资源而导致的性能问题。
同时私有静态实例变量还要加一个“volatile ” 关键字
如:

    private static volatile Singleton singleton = new Singleton();

getInstace方法代码修改如下:

public static  Singleton getInstance(){
        /*
            双重校验,同步代码块,高效利用锁资源,避免线程安全,双重校验实现单例
         */
        if(singleton == null){
            synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }

*: 加两层 if 的原因:
如果多个线程同时进入,如果只有一层if ,那么多个线程同样还是会“先后依次”进行实例化,这样也就违背了单例的原则。

加volatile的原因:
singleton = new Singleton();时,在jvm底层会有三个执行会进行:
1、给singleton对象分配内存空间
2、初始化对象
3、将对象指向分配的内存空间
由于JVM具有“指令重排”的特性,有可能这三个执行顺序会改变,比如 1>3>2,单线程下问题不大,但是多线程就会导致第二个线程判断对象不为空,返回对象,但是实际上这个对象是没有被初始化的。
:而volatile就是禁止JVM指令重排。

⑤ 上面的设计,除了“双重校验---线程安全”常用以外,一般其他不推荐使用,当然除了双重校验,还有:“静态内部类”、“枚举类”实现单例模式:
如下代码解释:
1、静态内部类

public class Singleton {
    //一个私有构造函数
    private Singleton(){}
    
    //一个私有静态内部类:返回被final 关键字修饰的 实例对象
    //静态内部类在类加载之后并不加载,只是在 getInstance 后才加载实例化
    private static class SingletonMake{
        private static final Singleton SINGLETON = new Singleton();
    }
    //一个公有静态方法:用来返回创建的实例
    public static  Singleton getInstance(){
        return SingletonMake.SINGLETON;
    }
}

2、枚举类(这是最受欢迎的单例设计)
原因: 代码量少、简洁、虚拟机底层自行解决线程安全问题、可以避免反射攻击(“双重校验锁” 其实存在这个问题)

public enum  Singleton {
   INSTANCE;

   //该类必要的对象
   private String name;

   //后面写该类的一些方法,比如:
    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }

    //测试
    public static void main(String[] args) {
        //实例化一个枚举类对象
        Singleton  oneSingleton = Singleton.INSTANCE;
        //执行更新操作
        oneSingleton.setName("one");
        System.out.println("oneSingleton.getName() :"+oneSingleton.getName());

        Singleton twoSingleton = Singleton.INSTANCE;
        System.out.println("oneSingleton == twoSingleton :" +(oneSingleton == twoSingleton));
    }
}
/********************************************************/
/**运行结果:
oneSingleton.getName() :one
oneSingleton == twoSingleton :true
*/

相关文章

  • 【设计模式】单例模式

    单例模式 常用单例模式: 懒汉单例模式: 静态内部类单例模式: Android Application 中使用单例模式:

  • Android设计模式总结

    单例模式:饿汉单例模式://饿汉单例模式 懒汉单例模式: Double CheckLock(DCL)实现单例 Bu...

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

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

  • 设计模式之单例模式详解

    设计模式之单例模式详解 单例模式写法大全,也许有你不知道的写法 导航 引言 什么是单例? 单例模式作用 单例模式的...

  • Telegram开源项目之单例模式

    NotificationCenter的单例模式 NotificationCenter的单例模式分析 这种单例模式是...

  • 单例模式Java篇

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

  • IOS单例模式的底层原理

    单例介绍 本文源码下载地址 1.什么是单例 说到单例首先要提到单例模式,因为单例模式是单例存在的目的 单例模式是一...

  • 单例

    iOS单例模式iOS之单例模式初探iOS单例详解

  • 单例模式

    单例模式1 单例模式2

  • java的单例模式

    饿汉单例模式 懒汉单例模式

网友评论

      本文标题:“单例模式”

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