常用设计模式(一)单例模式的实现方式和大概描述

给学习的知识点做个搬运总结,方便后面复习巩固知识


单例模式(创建型模式)

单例模式的特点
  1. 只有一个实例
  2. 自行实例化(必须创建自己的唯一实例)
  3. 向整个系统提供这个实例

通俗一点的说就是,保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

  • 其优点就是因为只生成一个实例,减少了系统性能开销,当一个对象需要较多资源时,如读取配置,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存来解决。
  • 单例模式可以在系统设置全局的访问点,优化功效资源访问。

单例模式的实现方式

单例模式一般是通过以下思路实现:

  • 构造器私有化(避免外部new构造器)
  • 提供私有的静态属性(存储对象的地址)
  • 提供公共的静态方法(获取属性)

一、 懒汉式

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

       单例模式的懒汉式体现了缓存的思想,延时加载就是一开始不要加载资源或者数据,一直等,等到马上就要使用这个资源的或者数据了,躲不过去了才去加载。

​ 懒汉式是定性的时间换空间,不加同步的懒汉式是线程不安全的,如下示例:
在这里插入图片描述

如何实现线程安全的懒汉式(双重检查加锁):
public class Singleton {
	
	private volatile static Singleton instance = null;
	
	private Singleton() {
		 
	}
	
	public static Singleton getInstance() {
		if (instance == null) {
			synchronized (Singleton.class) {
				if (instance == null) {
					instance = new Singleton();
				}
			}
			
		}
		return instance;
	}
}

二、 饿汉式

public class Singleton {
	
	private static Singleton instance = new Singleton();
	 
	// 私有化构造方法
	private Singleton() {
 
	}
 
	public static Singleton getInstance() {
		return instance;
	}
}

       饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要判断了,节省了运行时间。

三、 使用静态内部类实现单例模式

public class Singleton {
	
	private static class SingletonHoler{
		/**
		 * 静态初始化器,
		 */
		private static Singleton instance = new Singleton();
	}
	
	private Singleton() {
		
	}
	
	public static Singleton getInstance() {
		return SingletonHoler.instance;
	}
}

       当getInstance方法第一次被调用的时候,它第一次读取SingletonHolder.instance,导致SingletonHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Singleton的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。


四、 使用枚举来实现单例

public enum Singleton {

	uniqueInstance;// 定义一个枚举的元素,它就代表了Singleton的一个实例
	
	public void singletonOperation() {
		// 功能处理
		System.err.println("功能处理");
	}
}

五、 破坏单例模式的三种方式(未研究存档)

  1. 反射
  2. 序列化
  3. 克隆
/**
 * 对单例的破坏
 * @author Administrator
 *
 */
public class SingletonTest {
	
	public static void main(String[] args) throws Exception {
		
		System.out.println("-----------序列化----------------------");
	     Singleton originSingleton = Singleton.getInstance();
	     ByteArrayOutputStream bos = new ByteArrayOutputStream();
	     ObjectOutputStream oos = new ObjectOutputStream(bos);
	      oos.writeObject(Singleton.getInstance());
	      ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
	      ObjectInputStream ois = new ObjectInputStream(bis);
	      Singleton serializeSingleton = (Singleton) ois.readObject();
	      System.out.println(originSingleton == serializeSingleton);//false
	      
	      System.out.println("-----------反射----------------------");
	      //通过反射获取
	        Constructor<Singleton> cons = Singleton.class.getDeclaredConstructor();
	        cons.setAccessible(true);
	        Singleton reflextSingleton = cons.newInstance();
	        System.out.println(reflextSingleton == originSingleton);//false
	        
	        System.out.println("---------------------------克隆----------------------");
	        
	        Singleton cloneSingleton = (Singleton) originSingleton.clone();
	        System.out.println(cloneSingleton == originSingleton);//false
	    
	}
	
	private static class Singleton implements Serializable,Cloneable {
		/**
		 * 1.构造方法私有化,外部不能new
		 */
		private Singleton() {}
		
		
		//2.本类内部创建对象实例
		private static volatile Singleton instance;
		
		
		//3.提供一个公有的静态方法,返回实例对象
		public static Singleton getInstance() {
			if(instance == null) {
				synchronized (Singleton.class) {
					if(instance == null) {
						instance = new Singleton();
					}
				}
			}
			return instance;
		}
		
		@Override
		 protected Object clone() throws CloneNotSupportedException {
		     return super.clone();
		  }
		 
	}
	
}

解决方案如下:

1、防止反射

定义一个全局变量,当第二次创建的时候抛出异常

2、防止克隆破坏

重写clone(),直接返回单例对象

3、防止序列化破坏

添加readResolve(),返回Object对象

代码如下:
**
 * 对单例破坏的解决方案
 * @author Administrator
 *
 */
public class SingletonTest {
	
	public static void main(String[] args) throws Exception {
		
		System.out.println("-----------序列化----------------------");
	     Singleton originSingleton = Singleton.getInstance();
	     ByteArrayOutputStream bos = new ByteArrayOutputStream();
	     ObjectOutputStream oos = new ObjectOutputStream(bos);
	      oos.writeObject(Singleton.getInstance());
	      ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
	      ObjectInputStream ois = new ObjectInputStream(bis);
	      Singleton serializeSingleton = (Singleton) ois.readObject();
	      System.out.println(originSingleton == serializeSingleton);//false
	      
	      System.out.println("-----------反射----------------------");
	      //通过反射获取
	        Constructor<Singleton> cons = Singleton.class.getDeclaredConstructor();
	        cons.setAccessible(true);
	        Singleton reflextSingleton = cons.newInstance();
	        System.out.println(reflextSingleton == originSingleton);//false
	        
	        System.out.println("---------------------------克隆----------------------");
	        
	        Singleton cloneSingleton = (Singleton) originSingleton.clone();
	        System.out.println(cloneSingleton == originSingleton);//false
	    
	}
	
	private static class Singleton implements Serializable,Cloneable {
		
		private static volatile boolean isCreate = false;//默认是第一次创建
		/**
		 * 1.构造方法私有化,外部不能new
		 */
		private Singleton() {
			if(isCreate) {
				throw new RuntimeException("已然被实例化一次,不能在实例化");
			}
			isCreate = true;
		}
		
		
		//2.本类内部创建对象实例
		private static volatile Singleton instance;
		
		
		//3.提供一个公有的静态方法,返回实例对象
		public static Singleton getInstance() {
			if(instance == null) {
				synchronized (Singleton.class) {
					if(instance == null) {
						instance = new Singleton();
					}
				}
			}
			return instance;
		}
		
		@Override
		 protected Object clone() throws CloneNotSupportedException {
		     return instance;
		 }
		
		/**
		 * 防止序列化破环
		 * @return
		 */
		private Object readResolve() {
	        return instance;
	    }
		 
	}
	
}

六、 单例模式注意事项和细节说明

  1. 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使
    用单例模式可以提高系统性能
  2. 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用 new
  3. 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级
    对象),但又经常用到的对象、 工具类对象、频繁访问数据库或文件的对象(比如 数据源、session 工厂等)

七、需要补充的知识点

Java中Volatile关键字详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值