• java设计模式:单例模式(Singleton Pattern)


      

    单例模式(Singleton Pattern)

      

        1.单例模式概述

        2.懒汉式单例

        3.饿汉式单例

        4.单例在多线程中的实现方式

         4.1 同步方法

         4.2 双重锁定

         4.3 静态内部类

         4.4 枚举方式

        5.总结

    1.单例模式概述

      单例就是在系统内存中只存在一个对象,用来节约系统资源,减少频繁创建和销毁对象带来的系统开销。

      从功能上,单例模式维护系统有且仅有一个实例,并提供全局的访问点,其算是一种职责型模型。

    2.懒汉式单例

      懒汉式单例类,在第一次调用的时候实例化自己,这种单例模式线程不安全,多线程时不能保证类的实例是单例的。代码参如下。

    public class Singleton {
    
    	// 构造器私有化
    	private Singleton() {}
    
    	private static Singleton instance = null;
    
    	public static Singleton getInstance() {//提供全局的访问点
    		if (instance == null) {
    			instance = new Singleton();
    		}
    		return instance;
    	}
    }
    

      该实现方式的优点如下:

      ★由于实例是在 instance属性方法内部创建的,因此类可以使用附加功能(例如,对子类进行实例化),即使它可能引入不想要的依赖性。

      ★直到对象要求产生一个实例才执行实例化;这种方法称为“惰性实例化”。惰性实例化避免了在应用程序启动时实例化不必要的实例。

    3.饿汉式单例

      饿汉式单例是指在类初始化时就自行实例化,所以天生线程安全,该实现方式的优点是获取实例不需要每次都进行判断,节约运行时间,代码如下:

    //饿汉式单例,在类初始化时已经自行实例化,所以天生线程安全
    public class Singleton {
    
    	private Singleton() {
    	}
    
    	private static final Singleton singleton = new Singleton();
    
    	public static Singleton getInstance() {
    		return singleton;
    	}
    }
    

    4.单例在多线程中的使用

    (1)同步方法:

      单例在多线程中使用需要考虑线程安全问题,饿汉式单例虽然是线程安全的,但是它在该类加载的时候就会直接实例化一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢,所以这种方式适合在小系统中。

    当系统中这样的类比较多时,可以采用同步方法来处理进行延迟加载,代码如下:

    public class Singleton {
    
    	private Singleton() {
    
    	}
    
    	private static Singleton single = null;
    
    	// 静态工厂方法,加同步保证线程安全
    	public static synchronized Singleton getInstance() {
    
    		if (single == null) {
    			single = new Singleton();
    		}
    		return single;
    	}
    
    }
    

      这种方式虽然线程安全,但是同步方法会带来性能问题。解决这个问题可以参考后续几种方式。

    (2)双重锁定:

      代码如下:

    public class Singleton {
    	private static Singleton instance;
    
    	private Singleton() {
    	}
    
    	public static Singleton getInstance() { 
    		//先判断一次引用,所有引用不为null的情况都不用进入同步方法了
    		if (instance == null) {
    			//对获取实例的方法进行同步,此时引用为null多个请求每次只有一个可以进入同步方法,
    			synchronized (Singleton.class) {
    				//只要第一次实例化后,后续引用都不为null,此时再判断一次引用的情况,就可以保证只实例化一次
    				if (instance == null)
    					instance = new Singleton();
    			}
    		}
    		return instance;
    	}
    
    }
    

      

    (3)静态内部类方式:

      代码如下:

    //静态内部类实现方式(既线程安全,又避免同步带来的性能影响)
    public class Singleton {
    
    	private static class LazyHolder{
    		private static final Singleton INSTANCE = new Singleton();
    	}
    	
    	private Singleton() {}
    
    
    	// 静态工厂方法,加同步保证线程安全
    	public static final Singleton getInstance() {
    		return LazyHolder.INSTANCE;
    	}
    
    }
    

      

    (4)枚举方式

      代码如下:

    //创建枚举默认就是线程安全的,无需double checked locking。
    public enum SingletonEnum {
    	INSTANCE {
    		public void singleMethod() {
    			//some code write here
    		}
    	};
    	protected abstract void singleMethod();
    }
    

      

      

    5.总结

      单例模式根据单例产生的时机可分为懒汉模式和饿汉模式,其中懒汉模式会延迟加载这样可以避免不必要的单例实例化,节省空间;而饿汉模式在类装载的时候就实例化对象,在获取实例的时可以直接获取,节省时间。

      从线程安全方面考虑,饿汉式单例天生线程安全,而懒汉式需要一些处理才行。其中同步方法因为使用同步关键字从而使线程安全,但是会影响性能;双重锁定将实例类作为监视器,并通过两次判断从而保证线程安全,

    并且有较好的运行性能。另外枚举方式实现单例代码简单,而且有序列话和线程安全的保证,是比较好的单例实现方式,所以小伙伴们快快get起来吧!

  • 相关阅读:
    关于oracle当中数据类型转换的问题
    CASE WHEN的两种格式
    C#设置默认打印机
    运用Merge Into实现增加或更新数据
    增加或修改的存储过程
    深拷贝与浅拷贝
    sql server两种分页方法
    获取sql执行时间
    inserted触发器,一张表插入数据时,同时向另外一张表插入数据
    List<string[]> 如何去重
  • 原文地址:https://www.cnblogs.com/ICE_melt/p/6701436.html
Copyright © 2020-2023  润新知