美文网首页
设计模式之单例模式

设计模式之单例模式

作者: tanoak | 来源:发表于2018-07-30 20:14 被阅读18次

应用场景

  1. Windows的任务管理器就是很典型的单例模式,想想看,能打开两个任务管理器吗?

  2. windows的回收站也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。

  3. 操作系统的文件系统,也是单例模式实现的具体例子,一个操作系统只能有一个文件系统。

在Spring管理的Bean中,默认就是单例存在的,让我们来深入了解单例模式
举栗子,在小说神雕侠侣中只会有一个小龙女不然那就成西游记,一根毫毛一个分身

饿汉模式

package com.tanoak.create.single;
/**
 * @author tanoak@qq.com
 * @date 2018/7/18 15:29
 * @Desc 小龙女  单例 =>饿汉模式  不会存在多线程并发问题 但是占用内存
 */
public class DragonGirl1 {

    private String name ;
    private String sex ;
    private String desc ;
    private DragonGirl1(){}
    private static DragonGirl1 girl = new DragonGirl1();
    public static DragonGirl1 getInstance() {
        return girl;
    }
}

懒汉模式

/**
 * @author tanoak@qq.com
 * @date 2018/7/18 15:29
 * @Desc 小龙女  单例 =>懒汉模式
 */
public class DragonGirl2 {

    private String name ;
    private String sex ;
    private String desc ;
    private DragonGirl2(){}
    private static DragonGirl2 girl  = null;

    public static DragonGirl2 getInstance(){
        if (null == girl) {
            girl = new DragonGirl2();
        }
        return girl;
    }

}

会存在并发问题,因为调用newInstance()方法时没有加锁,导致会并发执行,如图:


2a.png

双重检查机制

/**
 * @author tanoak@qq.com
 * @date 2018/7/18 15:29
 * @Desc 小龙女  单例 =>双重检查机制
 */
public class DragonGirl3 {
    private String name ;
    private String sex ;
    private String desc ;
    private DragonGirl3(){}
    private static volatile  DragonGirl3 girl  = null;

    public  static DragonGirl3 getInstance(){
        if (null == girl) {
            synchronized (DragonGirl3.class){
                if(null ==girl){
                    girl = new DragonGirl3(); //1
                }
            }
        }
        return girl;
    }
}

这种方式是最常用的,我也比较喜欢用这种方式,在这里注意volatile这个关键字,
作用:禁止指令重排序(不对volatile做详细介绍),详细了解volatile可以参考这篇博文volatile详解
为什么要禁止指令重排序?
因为在jdk1.5之后,JAVA是无序写入,可能会造成顺序的颠倒,即内存分配、返回对象引用、初始化的顺序,这种情况下对应到//1就是singleton已经不是null,而是指向了堆上的一个对象,但是该对象却还没有完成初始化动作。当后续的线程发现singleton不是null而直接使用的时候,就会出现问题。
测试

/**
 * @author tanoak@qq.com
 * @date 2018/7/18 15:29
 * @Desc 单例模式
 */
public class Main {
    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 50; i++) {
            createThread();
        }
    }
    private static void createThread() throws Exception{
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName()+" :=> "+DragonGirl1.getInstance());
//          System.out.println(Thread.currentThread().getName()+" :=> "+DragonGirl2.getInstance());
//          System.out.println(Thread.currentThread().getName()+" :=> "+DragonGirl3.getInstance());
            try {
                Thread.sleep(6000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

在Java中还可以用枚举类型来实现单例,但是日常的开发中使用的比较少,可能是习惯原因,想了解的可以参考枚举单例这篇博文

相关文章

网友评论

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

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