Java描述设计模式(01):单例模式
本文源码:GitHub·点这里 || GitEE·点这里
一、单例模式
1、概念图解
单例设计模式定义:确保这个类只有一个实例,并且自动的实例化向系统提供这个对象。
2、样例代码
package com.model.test;
public class Singleton {
	// 使用静态变量记录唯一实例
	private static Singleton singleton = null;
	private Singleton (){}
	public static Singleton getInstance (){
		if (singleton == null){
			singleton = new Singleton() ;
		}
		return singleton ;
	}
	public static void main(String[] args) {
		Singleton singleton1 = Singleton.getInstance() ;
		Singleton singleton2 = Singleton.getInstance() ;
		/**
		 * com.model.test.Singleton@15db9742
		 * com.model.test.Singleton@15db9742
		 */
		System.out.println(singleton1);
		System.out.println(singleton2);
	}
}
Singleton称为单例类,构造函数使用private修饰,确保系统中只能产生一个实例,并且自动生成的。上面代码也就是所谓的懒汉式加载:只有到使用该对象的时候才来创建,意思饿了才来做饭吃。
二、线程安全问题
在上面的代码中存在一个很明显的线程安全问题,当有多条线程来请求对象实例的时候,因为对象的创建是需要时间的,假设A线程进来判断singleton == null,就会进入对象的创建过程,这时如果同时在过来几条线程,那么他们都会得到一个对象实例,这个就是所谓的线程安全问题。
1、同步控制方式
package com.model.test;
public class Singleton {
	// 使用静态变量记录唯一实例
	private static Singleton singleton = null;
	private Singleton (){}
	public static synchronized Singleton getInstance (){
		if (singleton == null){
			singleton = new Singleton() ;
		}
		return singleton ;
	}
}
这样操作会影响系统性能
2、饿汉式加载
public class Singleton {
	// 使用静态变量记录唯一实例
	private static Singleton singleton = new Singleton();
	private Singleton (){}
	public static Singleton getInstance (){
		return singleton ;
	}
}
这里先把对象创建出来,有需要直接使用;
3、双重检查
public class Singleton {
	// 使用静态变量记录唯一实例
	// volatile可以确保当singleton被初始化后,多线程才可以正确处理
	// 被volatile修饰的变量的值,将不会被本地线程缓存
	// 对该变量读写都是直接操作共享内存,确保多个线程能正确的处理该变量。
	private static volatile Singleton singleton = null ;
	private Singleton (){}
	public static Singleton getInstance (){
		// 如果实例不存在,则进入同步区
		if (singleton == null){
			// 只有第一次才会彻底执行这里面的代码
			synchronized (Singleton.class) {
				if (singleton == null){
					singleton = new Singleton() ;
				}
			}
		}
		return singleton ;
	}
}
4、枚举方式
package com.model.design.base.node01.singleton;
import org.junit.Test;
/**
 * 类级内部类里面创建对象实例
 */
public class C06_Singleton {
 @Test
 public void test01 (){
 SingletonDemo INSTANCE1 = SingletonDemo.INSTANCE ;
 SingletonDemo INSTANCE2 = SingletonDemo.INSTANCE ;
 System.out.println(INSTANCE1 == INSTANCE2);
 INSTANCE1.info();
 INSTANCE2.info();
 }
}
enum SingletonDemo {
 INSTANCE ;
 public void info (){
 System.out.println("枚举方式实现单例");
 }
}
三、延迟类初始化
1、基础概念
1)、类级内部类
  简单点说,类级内部类指的是,有static修饰的成员式内部类。如果没有static修饰的成员式内部类被称为对象级内部类。
  类级内部类相当于其外部类的static成分,它的对象与外部类对象间不存在依赖关系,因此可直接创建。而对象级内部类的实例,是绑定在外部对象实例中的。
  类级内部类中,可以定义静态的方法。在静态方法中只能够引用外部类中的静态成员方法或者成员变量。
  类级内部类相当于其外部类的成员,只有在第一次被使用的时候才被会装载。
2)、多线程缺省同步锁
  在多线程开发中,为了解决并发问题,主要是通过使用synchronized来加互斥锁进行同步控制。但是在某些情况中,JVM已经隐含地执行了同步,这些情况下就不用自己再来进行同步控制了。这些情况包括:
  1.由静态初始化器(在静态字段上或static{}块中的初始化器)初始化数据时
  2.访问final字段时
  3.在创建线程之前创建对象时
  4.线程可以看见它将要处理的对象时
2、实现方式
要想很简单地实现线程安全,可以采用静态初始化器的方式,它可以由JVM来保证线程的安全性。比如前面的饿汉式实现方式,在类装载的时候就初始化对象,不管是否需要,存在一定的空间浪费。
一种可行的方式就是采用类级内部类,在这个类级内部类里面去创建对象实例。这样一来,只要不使用到这个类级内部类,那就不会创建对象实例,从而同时实现延迟加载和线程安全。
public class LazySingleton {
	/**
	 * 类级内部类
	 */
	private static class SingletonHolder {
		private static LazySingleton lazySingleton = new LazySingleton() ;
	}
	public static LazySingleton getInstance (){
		return SingletonHolder.lazySingleton ;
	}
	public static void main(String[] args) {
		LazySingleton lazySingleton1 = LazySingleton.getInstance() ;
		LazySingleton lazySingleton2 = LazySingleton.getInstance() ;
		/**
		 * com.model.test.LazySingleton@15db9742
		 * com.model.test.LazySingleton@15db9742
		 */
		System.out.println(lazySingleton1+";;"+lazySingleton2);
	}
}
四、JDK源码单例模式
Runtime单例实现源码。
1、案例演示
/**
 * JDK 单例模式分析
 */
public class C07_Singleton {
 public static void main(String[] args) {
 Runtime runtime1 = Runtime.getRuntime() ;
 Runtime runtime2 = Runtime.getRuntime() ;
 /*
 * 1229416514
 * 1229416514
 */
 System.out.println(runtime1.hashCode());
 System.out.println(runtime2.hashCode());
 }
}
2、源代码分析
public class Runtime {
 private static Runtime currentRuntime = new Runtime();
 public static Runtime getRuntime() {
 return currentRuntime;
 }
 private Runtime() {}
}
基于饿汉模式实现的单例模式。
五、Spring框架中应用
1、创建测试类
public class UserBean {
}
2、Spring配置文件
<!-- 单例Bean -->
<bean id="user"
class="com.model.design.spring.node01.singleton.UserBean" />
3、测试读取Bean对象
package com.model.design.spring.node01.singleton;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Spring框架中单例模式
 */
public class S01_Singleton {
    @Test
    public void test01 (){
        ApplicationContext context01 = new ClassPathXmlApplicationContext("/spring/spring-context.xml");
        ApplicationContext context02 = new ClassPathXmlApplicationContext("/spring/spring-context.xml");
        UserBean user01 = (UserBean)context01.getBean("user") ;
        UserBean user02 = (UserBean)context01.getBean("user") ;
        UserBean user03 = (UserBean)context02.getBean("user") ;
        // com.model.design.spring.node01.singleton.UserBean@364841
        System.out.println(user01);
        // com.model.design.spring.node01.singleton.UserBean@364841
        System.out.println(user02);
        // com.model.design.spring.node01.singleton.UserBean@c4711c
        System.out.println(user03);
    }
}
结论
Spring单例模式与纯粹的单例设计模式的主要区别
尽管使用相同的类加载器来加载两个应用程序上下文,但是UserBean的实例是不一样的。也就是Spring框架中的单例对象是基于应用程序中。
六、单例模式总结
1、注意事项
单例模式注意事项和细节说明
1) 单例模式保证了 系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
2) 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new Object() 的方式。
3) 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象。
2、优缺点
优点:
1、单例模式只会创建一个对象实例,减少内存消耗
2、设置全局访问点,优化共享资源的访问
缺点:
1、没有接口,很难扩展
2、不利于测试
3、与单一职责原则冲突
七、源代码地址
GitHub地址:知了一笑
https://github.com/cicadasmile/model-arithmetic-parent
码云地址:知了一笑
https://gitee.com/cicadasmile/model-arithmetic-parent

Java描述设计模式(01):单例模式的更多相关文章
- Java与设计模式之单例模式(上)六种实现方式
		阎宏博士在<JAVA与模式>中是这样描述单例模式的:作为对象的创建模式,单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例.这个类称为单例类. ... 
- Java与设计模式之单例模式(下) 安全的单例模式
		关于单例设计模式,<Java与设计模式之单例模式(上)六种实现方式>介绍了6种不同的单例模式,线程安全,本文介绍该如何保证单例模式最核心的作用——“实现该模式的类有且只有一个实 ... 
- Java常见设计模式之单例模式
		1.何为单例模式? 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的 ... 
- Java描述设计模式(11):观察者模式
		本文源码:GitHub·点这里 || GitEE·点这里 一.观察者模式 1.概念描述 观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式.观察者模式定义了一种一对多 ... 
- Java描述设计模式(05):原型模式
		本文源码:GitHub·点这里 || GitEE·点这里 一.原型模式简介 1.基础概念 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出 ... 
- 《java常用设计模式之----单例模式》
		一.简介 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创 ... 
- Java描述设计模式(15):责任链模式
		本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景描述 1.请假审批流程 公司常见的请假审批流程:请假天数 当 day<=3 天,项目经理审批 当 3<day<= ... 
- Java描述设计模式(24):备忘录模式
		本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 常见的视频播放软件都具备这样一个功能:假设在播放视频西游记,如果这时候切换播放视频红楼梦,当再次切回播放西游记时, ... 
- Java描述设计模式(12):外观模式
		本文源码:GitHub·点这里 || GitEE·点这里 一.生活场景 1.场景描述 在移动互联网没有普及之前,去饭店吃饭的流程大致如下:选座位,排队,点菜,结账.后来移动互联网普及,通过手机APP就 ... 
随机推荐
- 面试题:为什么客户端最后还要等待2MSL
			面试题: 为什么客户端最后还要等待2MSL MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值. 保证客户端发送的最后一个ACK报文能够到达服务器, ... 
- 《Java知识应用》Java发送邮件(QQ,163)
			1 准备 Jar包下载地址: 链接: https://pan.baidu.com/s/1kFZgWRR8yZaQH_baf6tzAg 提取码: x2e8 邮箱:授权码 2.案例: 通过QQ邮箱服务器 ... 
- 遇见一只黑猫,她说Python是个怪物
			导读: Python猫是一只喵星来客,它爱地球的一切,特别爱优雅而无所不能的 Python.我是它的人类朋友豌豆花下猫,被授权润色与发表它的文章.如果你是第一次看到这个系列文章,那我强烈建议,请先看看 ... 
- Linux下的密码破解
			密码散列: 密码散列的$6 表示是:SHA512 这里我们使用hashcat 工具进行破解 ╰─ hashcat -m 1800 hash.txt /usr/share/wordlists/rocky ... 
- Electron中使用sql.js操作SQLite数据库
			推荐sql.js——一款纯js的sqlite工具. 一.关于sql.js sql.js(https://github.com/kripken/sql.js)通过使用Emscripten编译SQLite ... 
- Linux Ipsec
			准备环境 1 主机ip:192.168.0.107 2 VPN服务器: ens32:192.168.0.102 ens33:127.16.1.10 环境测试 modprobe ppp-compress ... 
- Linux下利用coredump技术追查进程崩溃原因
			原文链接:https://blog.csdn.net/u014585564/article/details/68063269 最近项目中出现了一个问题,服务器端程序会突然崩溃退出,我们采取了cored ... 
- 面试连环炮系列(六):Dubbo应用为什么要部署Zookeeper
			Dubbo应用为什么要部署Zookeeper? Zookeeper用来注册和发现服务,简单说就是提供端注册接口信息到Zookeeper,调用端在Zookeeper上查找接口对应的服务IP和端口.由于Z ... 
- 集合系列 Map(十二):HashMap
			HashMap 是 Map 基于哈希散列算法的实现,其在 JDK1.7 中采用了数组+链表的数据结构.在 JDK1.8 中为了提高查询效率,采用了数组+链表+红黑树的数据结构.本文所有讲解均基于 JD ... 
- 【译】gRPC vs HTTP APIs
			本文翻译自 ASP.NET Blog | gRPC vs HTTP APIs,作者 James,译者 Edison Zhou. 写在开头 现在,ASP.NET Core使开发人员可以构建gRPC服务. ... 
