参考网站:
1.
2.
2.
主要内容:
什么是单例模式?单例模式是一种设计模式,其设计的思路是:一个特殊的类,它只有一个实例,而且这个类提供了访问这个类的方法;
单例模式从实现上可分为饿汉式和懒汉式:
饿汉式:
//单例模式————"饿汉式"的代码规范class SingleHungry{ //此处有关键字final修饰aSingleInstanceObjRef,则表明次对象不可修改, //虽然不要final也可以实现效果,但这样做更加规范。 private static final SingleHungry aSingleInstanceObjRef = new Single(); private SingleHungry() {} public SingleHungry getSingle() { return aSingleInstanceObjRef; }}
优点:线程安全;
缺点:在未调用之前已经进行实例化,占用了相应的系统资源。
懒汉式:
//单例模式————"懒汉式"的代码//下列代码是“线程不安全”的写法。class SingleLanHan{ //此处不能有关键字final,否则aSingleInstanceObjRef引用就无法被复制了, //因为它被定为以为一个常量null private static SingleLanHan aSingleInstanceObjRef = null; private SingleLanHan() {} public SingleLanHan getSingleLanHan(){ if(aSingleInstanceObjRef == null) { // A aSingleInstanceObjRef = new SingleLanHan(); // B } return aSingleInstanceObjRef; }}
优点:在调用时才进行实例化;
缺点:线程不安全。原因:线程1和线程同时进入了A,线程1抢占了资源,执行了B,后来线程B也获得了资源,执行了B,这时候该类就被实例化两次,造成了线程不安全。
解决方案一(加锁):
//单例模式————"懒汉式"的代码//下列代码是“线程不安全”的写法。class SingleLanHan{ //此处不能有关键字final,否则aSingleInstanceObjRef引用就无法被复制了, //因为它被定为以为一个常量null private static SingleLanHan aSingleInstanceObjRef = null; private SingleLanHan() {} public synchronized SingleLanHan getSingleLanHan(){ if(aSingleInstanceObjRef == null) { // A aSingleInstanceObjRef = new SingleLanHan(); } return aSingleInstanceObjRef; }}
这个解决方案使用了synchronized关键字对来防止不同线程同时进入A处,由于单例模式只实例化一次,在往后的获取改实例的时候,都需要进行判断是否有其他的线程在占用着锁,效率低。
解决方法二(双重锁):
//单例模式————"懒汉式"的代码规范class SingleLanHan{ //此处不能有关键字final,否则aSingleInstanceObjRef引用就无法被复制了, //因为它被定为以为一个常量null private static SingleLanHan aSingleInstanceObjRef = null; private SingleLanHan() {} public SingleLanHan getSingleLanHan(){ if(aSingleInstanceObjRef == null) { //A synchronized(SingleLanHan.class) { if(aSingleInstanceObjRef == null) { aSingleInstanceObjRef = new SingleLanHan(); return aSingleInstanceObjRef; } } }else { return aSingleInstanceObjRef; } }}
这个解决方案在synchronized关键字之前加上了一条if语句(A处),在未实例化之前,synchronized的锁依然起作用,同时,在synchronized内部也需要一条判断语句,防止线程陆续进入synchronized块后重复实例化;而实例化后,它(A处)的作用就是隔离了synchronized块的操作。效率比方面方案一高。
解决方案三(内部类):
public class Singleton { static class SingletonHolder { static Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; }}
JVM内部的机制能够保证当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,同时,instance是在第一次加载SingletonContainer类时被创建的,而SingletonContainer类则在调用getInstance方法的时候才会被加载,因此也实现了lazy加载。
小小的单例模式还是有着这么大的学问,先记录下来,以备回顾之用。