设计模式-单例

单例模式

定义

确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例

优势

1. 内存中只有一个实例,减小内存开支
2. 减小对象频繁的建立、销毁
3. 建立资源时须要比较多的资源时减小,减小性能开销
4. 避免对资源的多重占用
5. 在系统设置全局访问点,优化和共享资源访问

缺点

1. 没有接口,扩展困难
2. 与单一原则职责有冲突,一个类应该只实现本身的逻辑,并不须要关心它是否单例的,
   是否是单例取决与环境,单例模式把 “要单例”和业务逻辑融合了(能够用内部类持有单例的方式解决此问题)

使用场景

系统要求某个类有且只有一个实例,不然就会出现“不良反应”
  • 具体场景举例java

    生成惟一的序列号
      项目中须要一个共享访问点或共享数据

扩展

须要产生多个固定数量或有上限数量对象的模式就叫多例模式。能够在设计系统的时候决定系统产生多少个
实例,方便进行扩展,修正单例存在的性能问题,提供响应速度

实现

· 简单类的单例安全

饿汉式
类被加载时就会被实例化一个对象

· 优势ide

线程安全

· 缺点性能

不能被延迟加载
没有被调用状况,浪费系统资源

· 实现方式测试

  1. 简单的类的单例
public class SimpleHungrySingleInstance {

	private static final SimpleHungrySingleInstance instance = new SimpleHungrySingleInstance();

	private SimpleHungrySingleInstance(){

	}

	public static SimpleHungrySingleInstance getSingleInstance(){
		return instance;
	}

}
  1. 枚举式

枚举只能拥有私有的构造器优化

枚举类其实是一个继承 Enum 的一个 final 类线程

枚举类不容许被反序列化,Enum 重写了方法设计

静态代码块中对 final 变量的值进行初始化指针

enum 类最终是一个 final classcode

/**
 * 利用枚举实现单例
 *
 */
public class ThreadSafeSingleInstanceFactoryFive {

	private ThreadSafeSingleInstanceFactoryFive(){

	}

	private  enum SingleFactoryEnum{

		SINGLE_FACTORY_ENUM {
			@Override
			public void doSomeThing() {
				 
			}
		};

		private  Cat cat = null;
		public  void doSomeThing(){
			System.out.println("cat.hashCode=" + cat.hashCode());
		}

		SingleFactoryEnum(){
			cat = new Cat();
		}
	}

	public static Cat getCat(){
		return SingleFactoryEnum.SINGLE_FACTORY_ENUM.cat;
	}

    public static void doSomeThing(){
		 SingleFactoryEnum.SINGLE_FACTORY_ENUM.doSomeThing();
	}
懒汉式
只在须要对象时才会生成单例对象

· 优势

能延迟加载

· 缺点

须要本身保证线程安全

· 实现方式

  1. synchronized 方法获取

    线程安全,锁粒度为Class,粒度较大,性能受影响

    public class ThreadSafeSingleInstanceModelOne {
    
    	private static ThreadSafeSingleInstanceModelOne threadSafeSingleInstanceModelOne = null;
    
    	private ThreadSafeSingleInstanceModelOne(){
    
    	}
    
    	/**
    	 *
    	 * @return
    	 */
    	public synchronized static ThreadSafeSingleInstanceModelOne getInstance(){
    
    		if(threadSafeSingleInstanceModelOne == null){
    			try {
    				Thread.sleep(300); //模拟实例化须要的时间
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			threadSafeSingleInstanceModelOne = new ThreadSafeSingleInstanceModelOne();
    		}
    			return threadSafeSingleInstanceModelOne;
    		}
    	}
  2. synchronized 同步块

    非线程安全

public class ThreadSafeSingleInstanceModelTwo {

	private static ThreadSafeSingleInstanceModelTwo instance = null;

	public static ThreadSafeSingleInstanceModelTwo getInstance(){
		if(instance == null){   // 多个线程可能会同时在这里判true,所以屡次进入同步块
			synchronized (ThreadSafeSingleInstanceModelTwo.class){

				try {
					Thread.sleep(300);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				instance = new ThreadSafeSingleInstanceModelTwo();
			}
		}

		return instance;
		}
	}
  1. 采用volatileh和DCL(双检查锁机制)
public class ThreadSafeSingleInstanceModelThree {

	/**
	 *   采用Volatile 和 DCL机制
	 *
	 * volatile 关键字做用 只能保证可见性
	 * 1,多个线程可见
	 * 2,禁止指令重排
	 *
	 * 通常对象的建立步骤   分配地址 -> 初始化属性 -> 指针指向分配地址
	 *
	 * 编译器优化致使指令重排 可能出现
	 * 			分配地址
	 * 			-> 指针指向分配地址(没有初始化 返回是个null对象  原始类型范围内的值(例如int 的范围为-128 ~ 127 ,超事后自动转化为对象建立))
	 * 			->  初始化属性
	 *
	 *
	 *
	 *   Double Check Locking 双检查锁机制(推荐)
	 *    同步块中不检查的状况可能还会屡次建立对象
	 *
	 */
	private volatile static ThreadSafeSingleInstanceModelThree instance = null;

	public static ThreadSafeSingleInstanceModelThree getInstance() {

		if (instance == null) {
			synchronized (ThreadSafeSingleInstanceModelThree.class) {
				try {
					Thread.sleep(300);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if (instance == null) {  //此处可能对象已经分配指针但没有初始化  采用 Double Check Locking 双检查锁机制
					instance = new ThreadSafeSingleInstanceModelThree();
				}
			}
		}
		return instance;
	}

}

4.静态内部类的实现

/**
 * 静态内部类的单例
 * 没有获取实例的时候内部类不会被初始化
 */
public class ThreadSafeSingleInstanceModelFour  {

	private static class ThreadSafeSingleInstanceModelFourInnerClass{
		public static final ThreadSafeSingleInstanceModelFour instance = new ThreadSafeSingleInstanceModelFour();
	}


	public static final ThreadSafeSingleInstanceModelFour getInstance(){
		try {
			Thread.sleep(300);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		return ThreadSafeSingleInstanceModelFourInnerClass.instance;
	}

}

5.序列化

public class ThreadSafeSingleInstanceModelSix implements Serializable {

	/**
	  *  序列化能够保证单例的安全
	 *  但反序列化的过程是readObject() 会建立一个新的对象,readResolve 特性容许你用   建立的实例代替另一个实例,
	 *    该方法忽略了被反序列化的对象,所以返回类初始化建立的那个特殊的实例
	 *    所以 实例的序列 化形式不该该包含任何实际的数据;全部的实例字段都应该被声明为 。
	 *    事实上, 若是依赖readResolve 进行实例控制,带有对象引用类型的全部实例字段都必须声明为 transient 。
	 *
	 */
	private volatile static ThreadSafeSingleInstanceModelSix instance = null;

	//标记为transient
	private transient String testName = "";

	public static ThreadSafeSingleInstanceModelSix getInstance() {

		if (instance == null) {
			synchronized (ThreadSafeSingleInstanceModelSix.class) {
				try {
					Thread.sleep(300);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				if (instance == null) {  //此处可能对象已经分配指针但没有初始化  采用 Double Check Locking 双检查锁机制
					instance = new ThreadSafeSingleInstanceModelSix();
				}
			}
		}
		return instance;
	}

	private Object readResolve() {
		// Return the one true Elvis and let the garbage collector
		// take care of the Elvis impersonator.
		return instance;
	}

}
如何选用
占用资源少,不须要延时加载
饿汉式 > 懒汉式

占用资源大,须要延时加载
懒汉式 > 饿汉式
测试代码
public class SimpleSluggardSingleInstanceThread extends Thread{
		@Override
		public void run() {
			log.info("Thread getInstance hashCode = {}", SimpleSluggardSingleInstance.getInstance().hashCode());
		}
	}

	public  SimpleSluggardSingleInstanceThread newSimpleSluggardSingleInstanceThread(){
		return new SimpleSluggardSingleInstanceThread();
	}
TestThreads.SimpleSluggardSingleInstanceThread[] threads = new TestThreads.SimpleSluggardSingleInstanceThread[len];
		for (int i = 0; i < threads.length; i++) {
			threads[i] = TestThreads.getThreadHandler().newSimpleSluggardSingleInstanceThread();
		}

		for (int i = 0; i < threads.length; i++) {
			threads[i].start();
		}
相关文章
相关标签/搜索