设计模式之创建型模式:单例模式

一、设计模式概述

设计模式是基于设计模式原则的基础上,由众多软件开发人员对所遇到的软件工程设计问题所总结的经验,它是某类问题的解决方案,代表了某类问题的最佳实践,它的最终目的是为了提高软件的可维护性,可读性,通用性,可扩展性等

设计模式最经典的书籍就是由“四人组GOF”所编写的【设计模式】,该书将设计模式总结为三种类型,共23种,我后续的设计模式就按照这23种设计模式逐一讲解。

23种设计模式分别如下:

  1. 创建型模式(5种):单例模式,抽象工厂模式,原型模式,建造者模式,工厂模式。
  2. 结构型模式(7种):适配器模式,桥接模式,装饰模式,组合模式,外观模式,享元模式,代理模式。
  3. 行为型模式(11种):模板方法模式,命令模式,访问者模式,迭代器模式,观察者模式,中介者模式,备忘录模式,解释器模式,状态模式,策略模式,职责链模式。

本文讲解创建型模式中的单例模式。

二、单例模式概述

单例设计模式就是保证在整个软件系统中,对某个类只能存在一个对象实例,该对象实例由类提供一个静态方法获取。

单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能

基于单例模式的特点,其应用场景如下:

  • 对于一些重量级的对象(创建时耗时或者耗费资源过多)
  • 需要频繁进行创建和销毁的对象
  • 经常用到的工具类对象
  • 频繁访问数据库或文件的对象

三、单例模式实现

1. 饿汉式实现

所谓饿汉式实现就是指,不论这个类对象是否会用到,在类加载的时候就进行实例化

饿汉式单例模式,直接对静态变量进行实例化,代码实现如下:

class Singleton {
	
	//1. 构造器私有化, 外部能new
	private Singleton() {
		
	}
	
	//2.本类内部直接创建对象实例
	private final static Singleton instance = new Singleton();
	
	//3. 提供一个公有的静态方法,返回实例对象
	public static Singleton getInstance() {
		return instance;
	}
	
}

饿汉式单例模式,将静态变量在静态代码块中进行实例化,代码实现如下:

class Singleton {
	
	//1. 构造器私有化, 外部能new
	private Singleton() {
		
	}
	

	//2.本类内部创建对象实例
	private  static Singleton instance;
	
	static { // 在静态代码块中,创建单例对象
		instance = new Singleton();
	}
	
	//3. 提供一个公有的静态方法,返回实例对象
	public static Singleton getInstance() {
		return instance;
	}
	
}

2. 懒汉式实现

所谓懒汉式实现是指只有用到某个类对象时才会创建,用不到就不会创建,可以减少系统资源浪费。具体实现方法包括多线性不安全和多线程安全两种类型,对应线程不安全的实现只适用于单线程使用。

2.1 多线程不安全的实现

  • 代码实现:
class Singleton {
	private static Singleton instance;
	
	private Singleton() {}
	
	//提供一个静态的公有方法,当使用到该方法时,才去创建 instance
	//即懒汉式
	public static Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}
  • 为什么多线程不安全?
    因为在多线性环境下,有可能多个线程同时进入if代码块,这样就会导致多个线程都进行实例化操作,产生不一样的对象

2.2 多线程安全的实现

2.2.1 synchronized实现

代码实现:

class Singleton {
	private static Singleton instance;
	
	private Singleton() {}
	
	//提供一个静态的公有方法,加入同步处理的代码,解决线程安全问题
	//即懒汉式
	public static synchronized Singleton getInstance() {
		if(instance == null) {
			instance = new Singleton();
		}
		return instance;
	}
}
  • 分析
    因为在获取实例化对象的方法上添加了同步关键字,就可以保证每次只有一个线程进入该方法,保证了多线程必然得到的是同一个实例化对象。但是这种实现方法的缺点是造成效率降低,因为每一个线程访问都要进行同步,但理论上只要一个线程完成实例化后,其它线程就不会再存在得到不同对象的问题了,因此可以不需要同步操作了。
    为了解决该实现方法造成的效率低的问题,提出双重检查实现方法,该方法既可以保证线程安全,又可以尽可能的少的使用同步代码块。
2.2.2 双重检查实现
  • 代码实现
class Singleton {
	private static volatile Singleton instance;//必须使用volatile关键字,防止指令重排
	
	private Singleton() {}
	
	//提供一个静态的公有方法,加入双重检查代码,解决线程安全问题, 同时解决懒加载问题
	//同时保证了效率, 推荐使用
	
	public static Singleton getInstance() {
		if(instance == null) {//如果尚未创建对象,可能多个线程进入下面的代码块
			synchronized (Singleton.class) {//保证一次只能有一个线程进入其代码块
				if(instance == null) {//假设一个线程已经实例化了对象,如果再有线程进来,就会发现instance不为null,就不会再实例化对象
					instance = new Singleton();
				}
			}
			
		}
		return instance;
	}
}
2.2.3 静态内部类实现
  • 代码实现
class Singleton {
	//构造器私有化
	private Singleton() {}
	
	//写一个静态内部类,该类中有一个静态属性 Singleton
	private static class SingletonInstance {
		private static final Singleton INSTANCE = new Singleton(); 
	}
	
	//提供一个静态的公有方法,直接返回SingletonInstance.INSTANCE
	
	public static Singleton getInstance() {
		
		return SingletonInstance.INSTANCE;
	}
}
  • 分析
    静态内部类在外面的类加载的时候不会初始化,只有使用到内部类时才会由jvm类加载器加载,而JVM可以保证线程的安全性,因此实现了线程安全,并且很明显实现了懒加载。

3. 枚举实现

  • 代码实现
enum Singleton {
	INSTANCE; //属性
}
  • 分析
    枚举实现单例模式是官方推荐的一种方法,枚举实现非常简单,并且基于JVM保证了线程安全。

四、单例模式在JDK源码中的应用示例

JDK中Runtime类就是实现了饿汉式单例模式,部分源码如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mekeater

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值