专栏首页java闲聊设计模式之单例模式
原创

设计模式之单例模式

应用场景

  1. Windows的Task Manager(任务管理器)就是很典型的单例模式(这个很熟悉吧),想想看,是不是呢,你能打开两个windows task manager吗? 不信你自己试试看哦~
  2. windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
  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中还可以用枚举类型来实现单例,但是日常的开发中使用的比较少,主要还是习惯原因,想了解的可以参考枚举单例这篇博文

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 输入URL到页面加载

    https://juejin.im/entry/58ce00c5ac502e00589b4bde

    tanoak
  • 享元模式

    tanoak
  • jdk10与springboot2.1.0尝鲜

    tanoak
  • 设计模式之单例模式

    单例模式指的是在应用整个生命周期内只能存在一个实例。单例模式是一种被广泛使用的设计模式。他有很多好处,能够避免实例对象的重复创建,减少创建实例的系统开销,节省内...

    用户1205080
  • 接口测试平台:Dubbo接口支持

    与http请求的处理基本一致,都是逐条case遍历进行处理,区别在于String result = ApiTestUtils.doDubboRequest(du...

    软件测试君
  • 深入理解python中的排序

    进行一个简单的升序排列直接调用sorted()函数,函数将会返回一个排序后的列表:

    desperate633
  • 工具| WebGoat源码审计之SQL注入篇

    漏斗社区
  • Goodfellow 炮轰同行评议!双盲评审导致AI顶会论文变水

    【新智元导读】Ian Goodfellow 今天发推表示,他怀疑正是同行评议机制导致了如今AI会议论文下降,评审人质量参差不齐是主要原因,浮夸的论文被选中,真正...

    新智元
  • [答疑]用序列图表达超时提醒

    另外,如果超时提醒的频率和你这个流程频率不一致,应该另外画一张超时提醒的序列图。到处乱插入超时提醒肯定是不对的

    用户6288414
  • RSA简介(四)——求逆算法

      此处所谓求逆运算,是指在模乘群里求逆。   第一节里提到互质的两个定义:   (1)p,q两整数互质指p,q的最大公约数为1。   (2)p.q两整数互质指...

    窗户

扫码关注云+社区

领取腾讯云代金券