设计模式-单例模式【七种创建方式】

1 单例模式

  单例模式是java中最简单的设计模式之一 ,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种设计模式涉及到一个单一的类,该类主要是用来创建单一的对象,同时提供给客户唯一的访问该对象的方式/方法,想要使用这个对象,直接访问该方法即可。

1.1 单例模式结构(单例模式主要角色

  • 单例类:仅创建一个实例的类
  • 访问类:使用单例类(不是必须)

1.2 单例模式的实现

  单例设计模式分类两种

  • 饿汉式:类加载时就会导致该单实例对象被创建
  • 懒汉式:类加载不会导致该单实例被创建,而是首次使用该单例时才创建

 1、饿汉式-方式1(静态变量的方式)

public class Singleton{
	//私有化构造方法
	private Singleton(){}
	//在成员变量位置创建唯一实例
	private static Singleton instance = new Singleton();
	//对外提供唯一的访问途径
	public static Singleton getInstance(){
		return instance;
	}
}
//备注:这种方式有一个缺点:当该类被加载时,对象就创建好了,如果对象比较大且不被使用,将会浪费内存

2、饿汉式-方式2(静态代码块方式)

public class Singleton{
	//私有构造方法
	private Singleton(){}
	//定义成员变量,是一个引用(不创建对象)
	private static Singleton instance;
	static{
		instance = new Singleton();
	}
	//提供唯一的访问该对象方式
	public stataic Singleton getInstance(){
		return instance;
	}
}
//缺点和饿汉式-方式1一致

3.懒汉式-方式1(线程不安全)

public class Singleton{
	//私有构造方法
	private Singleton(){}
	//在成员变量位置定义该类的引用
	private static Singleton instance;
	//对外提供静态的唯一访问方式
	public static Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
}
//当调用getInstance方法时才会创建对象赋值给instance变量,所以不会浪费内存,但在多线程环境下会出现安全隐患

4、懒汉式-方式2(线程安全)

//给访问入口加一synchronized
public class Singleton{
	//私有构造方法
	private Singleton(){}
	//在成员变量位置定义该类的引用
	private static Singleton instance;
	//对外提供静态的唯一访问方式
	public static synchronized Singleton getInstance(){
		if(instance == null){
			instance = new Singleton();
		}
		return instance;
	}
}
//缺点:虽然解决了多线程下的安全问题,但其是用来synchronized这个重量级锁来同步线程,导致效率比较低,因为synchronized的监视器是依赖与操作系统底层的,而操作系统底层线程的切换时比较复杂的:首先要从用户态切换到内核态,这个过程中间要保存很多信息,需要时间,而且当前synchronized锁的是类,整个方法只能由单个线程调用,综上效率低。

5、懒汉式-方式3(双重检查锁)

public class Singleton{
	//私有构造方法
	private Singleton(){}
	//在成员变量位置定义该类的引用
	private static Singleton instance;
	//对外提供静态的唯一访问方式
	public static Singleton getInstance(){
		//第一次判断,如果instance不为null,不进入枪锁阶段,直接返回实例
		if(instance == null){
			synchronized (Singleton.class){
				//抢到锁之后再判断是否为null
				if(instance == null){
					instance = new Singleton();
				}
			}
		}
		return instance;
	}
}
//缺点:多线程情况下,可能会出现空指针情况,这是因为jvm在实例化对象的时候会进行优化和指令重排序操作,为了防止指令重排,给成员变量加上 volatile 关键字

6、懒汉式-方式4(静态内部类方式)
 静态内部类单例模式中实例由内部类创建,由于jvm在加载外部类的过程中,是不会加载内部类的,只有内部类的属性/方法被调用时才会别加载,并初始化其静态属性。静态属性由于被static修饰,保证只被实例化一次,并且严格保证实例化顺序。

public class Singleton{
	//私有构造方法
	private Singleton(){}
	//定义静态内部类
	private static class SingletonHolder{
		private static final Singleton INSTANCE = new Singleton();
	}
	//访问入口
	public static Singleton getInstance(){
		return SingletonHolder.INSTANCE ;
	}
}
//优点:只有当第一次调用入口方法时,静态内部类才被加载且初始化,对象被创建且仅一次创建,在多线程环境下,无需加锁就解决安全问题,并且没有浪费任何内存

7、饿汉式(枚举方式)

public enum Singleton{
	INSTANCE;
}
//优点:枚举方式属于饿汉式方式,且是所有单例模式中的唯一一个不被破坏的单例实现模式

1.3 破化单例模式方式

  • 序列化和反序列化
  • 反射

通过序列化和反序列化以及反射这两种方式来破坏单例,可以创建多个实例对象。

1.3.1 反射方式破坏单例的解决办法

思路:反射破坏是通过取消访问检查,并获取构造方法来创建实例。只需要在构造方法里写判非空抛出异常的代码,即当通过反射活动构造器来创建实例时,每次都判断实例是否已经存在,存在就抛出异常不让它继续创建。

//构造方法添加异常抛出
private Singleton(){
	if(instance !=null){
		throw new RuntimeException();
	}
}

1.3.2 序列化和反序列化(略)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值