zoukankan      html  css  js  c++  java
  • 二、设计模式--单例模式

    1、定义

         • 确保一个类只有一个实例,且自行实例化,并向整个系统提供这个实例,这个类称为单例类,同时提供一个唯一的访问方法。 

    2、要点

         • 一个类只有一个实例

         • 必须自行创建实例

         • 必须自行向整个系统提供这个实例

    3、何时选用单例模式

         • 系统只需要一个实例对象

         • 客户调用类的单个实例,只允许使用一个公共访问点

         • 单例模式可扩展为多例模式,即一个类可以有一个实例共存

    4、本质

         • 控制实例的数量

    5、单例模式实现方式

         • 饿汉式

    package com.eager.test;
    
    /**
    * 饿汉式单例模式
    */
    public class EagerSingleton {
    	
    	//4:定义一个静态变量来存储创建好的类实例
    	//直接在这里创建类实例,只会创建一次
    	private static final EagerSingleton instance=new EagerSingleton();
    	
    	//1:私有化构造方法,好在内部控制创建实例的数目
    	private EagerSingleton()
    	{
    	}
    	
    	//2:定义一个方法来为客户端提供类实例
    	//3:这个方法需要定义成类方法,也就是要加static
    	//这个方法里面就不需要控制代码了
    	public static EagerSingleton getInstance()
    	{
    		return instance;
    	}
    }
    

      说明:

        1)static变量,在类加载的时候进行初始化

                2)多个static变量,共享一块内存区域

                3)饿汉式的一个缺点就是不管这个实例是否被使用,该实例都会被创建,会有一点点浪费内存

         • 普通懒汉式

    package com.lazy.test;
    
    /**
    * 普通懒汉单例模式
    */
    public class CommonLazySingleton {
    	
    	private static CommonLazySingleton instance=null;
    	
    	//私有的构造方法,以便在内部控制创建实例的个数
    	private CommonLazySingleton()
    	{
    	}
    	
    	//synchronized
    	public static CommonLazySingleton getInstance()
    	{
    		//如果没有值,说明还没有创建过实例,那就创建一个
    		//并把这个实例设置给instance
    		if(instance==null)
    		{
    			instance=new CommonLazySingleton();
    		}
    		
    		//如果有值则直接使用
    		return instance;
    	}
    }
    

      说明:普通懒汉式虽然利用延迟加载,解决了需要使用实例时才创建,但是这种方式是线程不安全的,假如A线程走到20行,但是还没有走到22行进行创建instance,此时,线程B也很快判断出instance==null,就会出现线程不安全的现象。

          • 双重检查加锁懒汉式

    package com.lazy.test;
    
    /**
    * 双重检查锁定懒汉单例模式
    */
    public class DoubleCheckLockingLazySingleton {
    
    	/**
    	* 对保存实例的变量添加volatile的修饰
    	*/
    	private volatile static DoubleCheckLockingLazySingleton instance = null;
    	
    	private DoubleCheckLockingLazySingleton()
    	{
    	}
    	
    	public static DoubleCheckLockingLazySingleton getInstance()
    	{
    		//先检查实例是否存在,如果不存在才进入下面的同步块
    		if(instance == null)
    		{
    			//同步块,线程安全的创建实例
    			synchronized(DoubleCheckLockingLazySingleton.class)
    			{
    				//再次检查实例是否存在,如果不存在才真的创建实例
    				if(instance == null)
    				{
    					instance = new DoubleCheckLockingLazySingleton();
    				}
    			}
    		}
    		return instance;
    	}
    }
    

      说明:

       1)双重检查加锁方式解决了延迟加载与线程安全问题,但是用到了Java中的关键字volatile,被volatile修饰的变量的值,不会被本地线程所缓存,所以对该变量的读取都是从共享内存中读取,从而保证多线程的安全性。

             2)Java1.4及以前版本中,很多JVM对于volatile关键字的实现有问题,会导致双重检查加锁的失败,因此双重检查加锁的机制只能用再Java5及以上版本

             3)由于volatile关键字可能会哦ing比掉JVM中一些必要的代码优化,因此运行效率不高。所以没有特别的需要,不建议使用。所以双重检查加锁策略虽然可以解决问题,但是不建议大量采用。

          • IoDH懒汉式

    package com.lazy.test;
    
    /**
    * IoDH懒汉单例模式
    */
    public class IoDHLazySingleton {
    	
    	private IoDHLazySingleton()
    	{
    	}
    	
    	/**
    	* 静态内部类,该内部类的实例与外部类的实例没有绑定关系,而且只有被调用才会装载,实现延迟加载
    	* 
    	* 多个实例的static变量会共享同一块内存区域
    	*/
    	private static class HolderClass
    	{
    		private final static IoDHLazySingleton instance=new IoDHLazySingleton();
    	}
    	
    	/**
    	* 提供给其他类获取唯一实例的方法
    	*/
    	public static IoDHLazySingleton getInstance()
    	{
    		return HolderClass.instance;
    	}
    }
    

      说明:利用静态内部类既实现了延迟加载,又实现了线程安全,因此推荐的使用方法之一即为此种方式。

          • 枚举实现的饿汉式       

    package com.enum_test;
    
    /**
    * 使用枚举来实现单例模式的示例
    */
    public enum SingletonEnum {
    	/**
    	* 定义一个枚举的元素,它就代表了SingletonEnum的一个实例
    	*/
    	INSTANCE;
    	
    	/**
    	* 示意方法,单例可以有自己的操作
    	*/
    	public String print() {
    		System.out.println("Enum测试实例调用方法");
            return "Enum单例模式测试";
        }
     
        // public static Singleton getInstance() {
        // return INSTANCE;
        // }
    }
    

      说明:

        1)Java的枚举型实质上是功能齐全的类,可以有自己的属性和方法

                2)Java的枚举型的基本思想是通过public static final 域为每个枚举常量导出实例对象的

                3)因此,用枚举实现单例模式会更加简洁、方便、并且提供了序列化的机制,由JVM保证线程安全。

  • 相关阅读:
    Shell for
    rsync 目录 斜杠
    shell local
    linux secureCRT utf-8编码显示
    eclipse maven 项目不显示 target目录
    如何打印身份证实际大小
    linux 去掉 ^M
    hibernate 之 集合映射中list映射
    hibernate 之 复合主键映射
    hibernate 之 组件映射
  • 原文地址:https://www.cnblogs.com/guoxiaoyue/p/4073258.html
Copyright © 2011-2022 走看看