一般大家接触过的单例模式有懒汉式,饿汉式以及双重检查锁的方式来实现单例模式。其中懒汉式不是线程安全的。代码如下:
public class Singleton { private Singleton(){} private static Singleton singleton = null; public static Singleton getInstance(){ if(singleton ==null ){ singleton = new Singleton(); } return singleton; }}懒汉式是典型的时间换空间,也就是每次获取实例都会先进行一次判断,当然如果没人调用的话则不会创建实例,节省了空间。而且懒汉式是线程不安全的。
下面来看一下饿汉式实现单例的代码
public class Singleton { private Singleton(){} private static Singleton singleton = new Singleton(); public static Singleton getInstance(){ return singleton; }}饿汉式显然是线程安全的,应为它在装载类的时候就已经初始化好了,而且装载类的时候不可能出现并发的情况。但是饿汉式是典型的空间换时间,,当类装载的时候就会创建实例,不管你用不用先创建好再说。每次调用的时候也就不需要判断了。节省了运行时间。
当然,懒汉式也可以实现成为线程安全的的方法,就是在获取实例的方法上加入synchronized即可,但是这样一来降低了整个访问速度,而且每次都要判断,更好的一种方法就是双重检查加锁。先看代码:
public class Singleton { private Singleton(){} private volatile static Singleton singleton = null; public static Singleton getInstance(){ if(singleton ==null ){ synchronized (Singleton.class) { if(singleton ==null ){ singleton = new Singleton(); } } } return singleton; }}这种实现方式既可以实现线程安全的创建实例,而又不会对性能造成太大的影响,它只在第一次创建实例的时候同步,以后就不需要同步了,从而加快了运行速度。但是要注意的是,这次用到了一个关键字:volatile,volatie关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高,因此一般建议,没有特别必要,不要使用,也就是说虽然可以使用双重加锁机制来实现线程安全的单例,但并不太建议频繁使用,可以根据情况选用。
接下来就是你想看到的东西,哈哈反正我是很受教。其实很简单,前面饿汉式已经实现了线程安全的实现了实例的初始化工作,但是它在类加载的时候就创建了实例,同样我是解决了在类加载的时候不去初始化对象,这样是不是就可以解决了?看代码:
public class Singleton { private Singleton(){} private static class SingletonHolder{ private static Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.instance; }}
想不到的方案往往就是非常简单,用一个类级别的内部类去创建对象实例,这样一来,只要不使用到这个内部类,你就不会创建对象实例,从而同时实现延迟加载和线程安全。
最后说一下单元素的枚举类型已经成为实现Singleton的最佳方法,关于枚举大家可以查看其它资料此处不再赘述。