• 设计模式01 创建型模式


    参考

    [1] 设计模式之:创建型设计模式(6种) | 博客园

    [2] 单例模式的八种写法比较 | 博客园

    单例模式(Singleton  Pattern)

    确保一个类有且仅有一个实例,并且为客户提供一个全局访问点。

    特点

    1) 保证被访问资源对象在内存中只有一个实例,节约了系统内存资源,也避免了对资源多重占用;

    2) 封装了访问实例方法,提供全局访问点,严格控制客户的访问方式;

    3) 通常常驻内存,不会频繁创建/销毁,节约了系统开销;

    缺点

    1) 没有抽象层,难以扩展;

    2) 类的职责过重,往往一个单例负责所有与之相关功能,违背了类设计的“职责单一”原则;

    3) 单例如果持有context,容易造成内存泄漏;

    4) 全局共享一个实例资源,难以隔离问题,进行单独测试;

    适用场景

    1)全局随时可能需要访问,访问方式复杂,而且资源受限;

    2)需要常驻内存,避免频繁创建、销毁的资源;

    demo

    单例模式通用UML类图

     

    单例模式的8种写法与多线程

    单例模式为了不让外部随意构建实例,一般需要将构造函数声明为private,在获取实例对象时,就无法通过动态函数来读取(因为此时实例还未初始化),故只能通过类方法(static方法)来获取实例引用。

     1. 饿汉式 静态常量 立即加载

    // Singleton.java
    // 饿汉式 静态常量
    public class Singleton {
    	private final static Singleton INSTANCE = new Singleton();
    	
    	private Singleton()	{	}
    	public static Singleton getInstance() { return INSTANCE; }
    	
    	public void displaySingleton(){
    		System.out.println("单例初始化方式: 饿汉式 静态常量");
    	}
    }

    特点:简单,类装载时完成初始化,不存在多线程同步问题;

    优点:没有延迟实例化,如果程序一直没有使用,会造成资源浪费;

    2.饿汉式 静态代码块 立即加载

    与饿汉式 静态常量类似,只是把实例初始化放在了类的静态代码块中,而非放在实例引用定义处。

    // Singleton1.java
    // 饿汉式 静态代码块
    public class Singleton1 {
    	private static Singleton1 instance;
    	
    	static{
    		instance = new Singleton1();
    	}
    	
    	private Singleton1(){}
    	
    	public static Singleton1 getInstance(){
    		return instance;
    	}
    	
    	public void displaySingleton(){
    		System.out.println("单例初始化方式: 饿汉式 静态代码块");
    	}
    }
    

     

     3. 懒汉式 延迟加载 线程不安全

    如果在执行多个线程同时执行到instance == null,就会造成多次实例化。只适合单线程情况使用。

    // Singleton2.java
    // 懒汉式 延迟实例化 线程不安全
    public class Singleton2 {
    	private static Singleton2 instance;
    	
    	private Singleton2(){}
    	
    	public static Singleton2 getInstance(){
    		if(instance == null){
    			instance = new Singleton2();
    		}
    		return instance;
    	}
    }
    

    4.懒汉式 延迟加载 线程安全(同步方法)

    效率低下,每次线程通过getInstance获取实例,甚至在对象已经实例化后,都要先等待别的线程释放资源。

    // Singleton3.java
    // 懒汉式 延迟实例化 线程安全(同步方法)
    public class Singleton3 {
    	private static Singleton3 instance;
    	
    	private Singleton3(){}
    	
    	public static synchronized Singleton3 getInstance(){
    		if(instance == null){
    			instance = new Singleton3();
    		}
    		return instance;
    	}
    	
    	public void displaySingleton(){
    		System.out.println("Singleton3单例初始化方式: 懒汉式 延迟实例化 线程安全(同步方法)");
    	}
    }
    

    5. 懒汉式 延迟实例化 线程安全(同步代码块) 

    效率比4(同步方法)高,但是多线程可能会出现多次实例化的问题。

    //Singleton4.java
    //懒汉式 延迟实例化 线程安全(同步代码块)
    public class Singleton4 {
    	private static Singleton4 instance;
    	private Singleton4(){}
    	
    	public static Singleton4 getInstance(){
    		if(instance == null) {
    			synchronized (Singleton4.class) {
    				instance = new Singleton4();
    			} 
    		}
    		
    		return instance;
    	}
    	
    	public void displaySingleton(){
    		System.out.println("Singleton4单例初始化方式: 懒汉式 延迟实例化 线程安全(同步代码块)");
    	}
    }
    

    6. 懒汉式 线程安全(双重检查)

    综合了4,5即线程安全(同步方法)和线程安全(同步代码块)的优缺点,解决了4的低效问题,又解决了5的多次实例化不安全问题。

    // Singleton5.java
    // 懒汉式 线程安全(双重检查)
    public class Singleton5 {
    	private static Singleton5 instance;
    	
    	private Singleton5(){}
    	
    	public static Singleton5 getInstance(){
    		if(instance == null){
    			synchronized(Singleton5.class){
    				if(instance == null) {
    					instance = new Singleton5();
    				}
    			}
    		}
    		return instance;
    	}
    	
    	public void displaySingleton(){
    		System.out.println("Singleton5单例初始化方式: 懒汉式 线程安全(双重检查)");
    	}
    }
    

    7. 静态内部类

    与饿汉式类似,都是通过类的装载机制来初始化实例,不过,既解决了饿汉式无法延迟实例化的问题,又解决了线程安全的问题。

    // Singleton6.java
    // 静态内部类 
    public class Singleton6 {
    	private Singleton6(){}
    	
    	private static class SingletonInstance{
    		private static final Singleton6 INSTANCE = new Singleton6();
    	}
    	
    	public static Singleton6 getInstance(){
    		return SingletonInstance.INSTANCE;
    	}
    	
    	public void displaySingleton(){
    		System.out.println("Singleton6单例初始化方式: 静态内部类 线程安全");
    	}
    }
    

    8. 枚举类型

    通过枚举类型在构造的时候,被实例化。不仅能解决多线程问题,还能防止反序列化创建新的对象。JDK1.5之后才加入,现使用较少。

    // Singleton7.java
    // 枚举类型
    public enum Singleton7 {
    	INSTANCE;
    	public void display(){
    		System.out.println("Singleton7单例初始化方式: 枚举类型");
    	}
    }
    

    总结

    1. 实现单例模式的核心在与私有化构造方法,在getInstance方法中读取实例引用。

    2. 如果是类加载时,就实例化,就成为饿汉式;否则,在getInstance方法中才实例化称为懒汉式。

    3. 各种实现方法比较

     实现方法 特点 是否线程安全 是否推荐
    饿汉式,静态常量 立即加载 可以用
    饿汉式,静态代码块 立即加载 可以用
    一般懒汉式 延迟加载 多线程不可用
    懒汉式,同步方法 延迟加载,效率低 可以用,不推荐
    懒汉式,同步代码块 延迟加载,多次实例化 不可用
    懒汉式,双重验证 延迟加载,效率高 推荐
    静态内部类 延迟加载,效率高 推荐
    枚举类型 延迟加载,效率高,应用较少(>JDK1.5) 推荐
  • 相关阅读:
    Cannot change network to bridged: There are no un-bridged host network adapters解决方法
    The authenticity of host 192.168.0.xxx can't be established.
    Vm下 linux与windowsxp文件共享的方法
    vmware 下的linux的host only上网配置
    VMWare三种工作模式 :bridge、host-only、nat
    云技术入门指导:什么是云计算技术,云技术用什么语言开发
    什么是移动云计算
    云计算是什么
    架构之路
    这首诗看着是越看越顺眼,百赋乐其中
  • 原文地址:https://www.cnblogs.com/fortunely/p/9785794.html
Copyright © 2020-2023  润新知