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起来吧!

原文地址:https://www.cnblogs.com/ICE_melt/p/6701436.html