单例模式

单例模式

单例模式的理解

单例模式,字面上理解当是使用过程中,只有一个实例存在于系统中

联系实际生活中的例子:

  1. 每个人只有一个身份证
  2. 同一个宇宙 只有一个太阳 一个地球 一个中国
  3. 每个人的指纹都是唯一的(不包括克隆人的情况)

电脑世界中的例子

  1. 一个电脑对应一个mac地址
  2. 一个时刻一个时间戳
  3. 数据库表中的主键唯一对应一条记录
  4. Spring IOC容器中的对象是单例的

如果这个系统中只有一份的单例,那么则相安无事,假如这个系统又加上例外的实例,也许就会像电影世界中说的,平行宇宙中出现俩个你,也许这个世界就会发生崩塌,所以有些东西只能有一份,超过一份,这个世界甚至会易燃易爆炸。

Java中单例模式

创建关键点:

  1. 限制创建 Java中是在构造器中加上private
  2. 自己创建实例 也就是创建者只能是自己 持有自身对象
  3. 需要一个返回该单例对象的静态static方法

饿汉式

关键点:
  • 构造器私有(限制只能在该类中进行实例化)
  • 在加载类的时候就进行初始化
  • 定义一个获取单例的方法
Good:
  • 简单明了
Bad:
  • 如果创建的过程很繁琐,那么就有可能需要时间比较多,没有使用的话,会浪费这部分资源
Code:
/**
 * 单例模式
 * @author 洪晓鸿     
 * @date   2019年4月16日 下午1:53:14   
 * @version V1.0
 */
public class HungrySingleton {

	// 创建一个引用用于保存单个的实例 这里使用static保证只有一个引用
	private static HungrySingleton instance = new HungrySingleton();
	
	// 将构造器私有化 只能在该类中创建实例/对象
	private HungrySingleton() {
		super();
	}
	
	// 饿汉式单例模式 对象创建的时候就初始化
	// 必须使用static 如果不使用static 则没有办法使用
	public static HungrySingleton getSingleton() {
		return instance;
	}
}

懒汉式

关键点:
  • 构造器私有(限制只能在该类中进行实例化)
  • 在调用方法的时候就进行初始化
  • 定义一个获取单例的方法
Good:
  • 简单明了
  • 节省资源
Bad:
  • 并发情况下有可能出现创建多个实例的情况
Code:
/**
 * 单例模式
 * @author 洪晓鸿     
 * @date   2019年4月16日 下午1:53:14   
 * @version V1.0
 */
public class Singleton {

	// 创建一个引用用于保存单个的实例 这里使用static保证只有一个引用
	private static Singleton instance;
	// 将构造器私有化 只能在该类中创建实例/对象
	private Singleton() {
		super();
	}
	// 懒汉式单例模式 也就是当要用到的时候才进行初始化
	// 必须使用static 如果不使用static 则没有办法使用
	public static Singleton getSingleton() {
		// 如果为空 则进行初始化
		if (instance==null) {
			instance = new Singleton();
		}
		return instance;
	}
}

线程安全懒汉式

关键点:
  • 构造器私有(限制只能在该类中进行实例化)
  • 在调用方法的时候就进行初始化
  • 在方法前面使用同步synchronized
  • 定义一个获取单例的方法
Good:
  • 使用同步保证只有一个实例被创建
  • 到使用时才进行初始化,节省部分资源
Bad:
  • 因为直接在方法上加了synchronized关键字 同一时刻只能有一个访问 无法实现多个同时访问
Code:
/**
 * 单例模式--线程安全式 效率比较低 如果多个进程访问 必须先等上一个线程访问完才能访问
 * @author 洪晓鸿     
 * @date   2019年4月16日 下午5:28:38   
 * @version V1.0
 */
public class SynchronizationSingleton {

	// 创建一个引用用于保存单个的实例 这里使用static保证只有一个引用
	// volatile保证 instance 在所有线程中同步
	private volatile static SynchronizationSingleton instance;
	// 将构造器私有化 只能在该类中创建实例/对象
	private SynchronizationSingleton() {
		super();
	}
	// 懒汉式单例模式 也就是当要用到的时候才进行初始化
	// 必须使用static 如果不使用static 则没有办法使用
	public synchronized static SynchronizationSingleton getSingleton() {
		// 如果为空 则进行初始化
		if (instance==null) {
			instance = new SynchronizationSingleton();
		}
		return instance;
	}
}

双重判断线程安全懒汉式

关键点:
  • 构造器私有(限制只能在该类中进行实例化)
  • 在调用方法的时候就进行初始化
  • 在方法内使用同步synchronized
  • 进入方法后先进行判断对象是否为null 再在同步代码块中判断对象是否为null
  • 定义一个获取单例的方法
Good:
  • 使用同步保证只有一个实例被创建
  • 到使用时才进行初始化,节省部分资源
  • 因为在方法内加上了双重判断,使得可以同一时间多次调用该方法
Bad:
  • 效率自然是比不上不同步的,好与坏其实很难讲,主要看场景吧,如果没在并发情况下,自然可以使用非线程安全的
Code:
/**
 * 单例模式--双重线程安全式 
 * @author 洪晓鸿     
 * @date   2019年4月16日 下午5:28:38   
 * @version V1.0
 */
public class DoubleSynchronizationSingleton {

	// 创建一个引用用于保存单个的实例 这里使用static保证只有一个引用
	private static DoubleSynchronizationSingleton instance;
	// 将构造器私有化 只能在该类中创建实例/对象
	private DoubleSynchronizationSingleton() {
		super();
	}
	// 懒汉式单例模式 也就是当要用到的时候才进行初始化
	// 必须使用static 如果不使用static 则没有办法使用
	public static DoubleSynchronizationSingleton getSingleton() {
		// 如果为空 才进入同步
		if (instance==null) {
			synchronized(DoubleSynchronizationSingleton.class) {
				// 取得锁之后再次判断是否已经初始化 没有则进行初始化
				if (instance==null) {
					// 初始化
					instance = new DoubleSynchronizationSingleton();
				}
			}
		}
		return instance;
	}
}

静态内部类式

关键点:
  • 构造器私有(限制只能在该类中进行实例化)
  • 在调用方法的时候就进行初始化
  • 静态内部类持有单例对象 并且为static 保证只有一次初始化
Good:
  • 使用静态内部类 可以将类的初始化延迟到调用方法的一刻 节约资源
Bad:
  • 想无
Code:
/**
 * 通过静态内部类实现单例
 * @author 洪晓鸿     
 * @date   2019年12月6日 下午10:10:23   
 * @version V1.0
 */
public class StaticInnerSingleton {

	/**
	 * 私有化构造器
	 */
	private StaticInnerSingleton() {
		System.out.println("单例模式初始化");
	}
	
	/**
	 * 获取单例对象
	 * @return
	 */
	public static StaticInnerSingleton getSingleton() {
		return Inner.singleton;
	}
	
	/**
	 * 通过静态内部类加载 
	 * @author 洪晓鸿     
	 * @date   2019年12月6日 下午10:17:00   
	 * @version V1.0
	 */
	private static class Inner {
		private static final StaticInnerSingleton singleton = new StaticInnerSingleton();
	}
	
	/**
	 * 测试一下
	 * @param args
	 */
	public static void main(String[] args) {
		StaticInnerSingleton s0 = getSingleton();
		StaticInnerSingleton s1 = getSingleton();
		if (s0==s1) {
			System.out.println("Equals");
		} else {
			System.out.println("Not Equals");
		}
	}

}

枚举式-终极奥义

关键点:
  • 如果需要某些属性,可以在枚举类中定义
  • 使用的时候直接使用类名加上.再加上对象就可以使用
Good:
  • 使用方便 不存在线程问题
Bad:
  • 暂时没想到
Code:
/**
 * 使用枚举类型创建一个单例
 * @author 洪晓鸿     
 * @date   2019年5月6日 下午4:28:22   
 * @version V1.0
 */
public enum SimgletonEnum {

	/**
	 * 需要使用自定义的构造器对其进行初始化
	 * 用   , 隔开不同的枚举
	 * 用   ; 隔开枚举类型与 枚举类型的属性和方法
	 */
	INSTANCE(1),;
	/**
	 * 一下的操作跟普通类一样
	 */
	private int key;
	
	SimgletonEnum(int key) {
		// 不可以加上修饰符 访问控制修饰符也不行呢
		this.key = key;
	}

	public int getKey() {
		return key;
	}

	public void setKey(int key) {
		this.key = key;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值