单列模式定义:确保一个类只有一个实例,并提供一个全局访问点。
下面是几种实现单列模式的Demo,每个Demo都有自己的优缺点:
Demo1:
/** * 单列模式需要满足下面三个条件: * 1.私有的构造函数 * 2.私有的引用变量 * 3.公开的静态方法(唯一获取该类单个实例的地方) * * @author Administrator */ public class AmericaPresident { private static AmericaPresident thePresident; /** * 功能:私有的构造函数 */ private AmericaPresident() { } /** * 功能:返回AmericaPresident对象 * @return */ public static AmericaPresident getPresident() { if(thePresident == null) { thePresident = new AmericaPresident(); } return thePresident; } } Demo1 在多线程的时候可能会出现一些程序上的bug
Demo2:
为了解决上面Demo1在多线程时候的bug,可以做出以下的修改: /** * 单列模式需要满足下面三个条件: * 1.私有的构造函数 * 2.私有的引用变量 * 3.公开的静态方法(唯一获取该类单个实例的地方) * * @author Administrator */ public class AmericaPresident { private static AmericaPresident thePresident; /** * 功能:私有的构造函数 */ private AmericaPresident() { } /** * 功能:返回AmericaPresident对象 * @return */ public static synchronized AmericaPresident getPresident() { if(thePresident == null) { thePresident = new AmericaPresident(); } return thePresident; } } 通过增加synchronized 关键字到getPresident()方法中,我们迫使每个线程在进入这个方法之前, 要先等候别的线程离开该方法。也就是说,不会有两个线程可以同时进入这个方法。 Demo2解决了多线程下的程序bug,但是又带了一个新的问题,同步一个方法可能造成程序执行效率 下降100倍。
Demo3:
/** * 单列模式需要满足下面三个条件: * 1.私有的构造函数 * 2.私有的引用变量 * 3.公开的静态方法(唯一获取该类单个实例的地方) * * @author Administrator */ public class AmericaPresident { private static AmericaPresident thePresident = new AmericaPresident(); /** * 功能:私有的构造函数 */ private AmericaPresident() { } /** * 功能:返回AmericaPresident对象 * @return */ public static synchronized AmericaPresident getPresident() { return thePresident; } } Demo3使用"急切"创建实例,而不用延迟实例化的做法,如果应用程序总是创建并使用单列实例,或者 在创建和运行方面的负担不太繁重,就可以用"急切"的方法来创建单列。 利用这个做法,我们可以依赖JVM在加载这个类时马上创建此唯一的单列实例,JVM保证在任何线程 访问thePresident静态变量之前,一定先创建此实例。
Demo4:
用"双重检验加锁",在getPresident()中减少使用同步。 利用双重检查加锁(double-checked locking),首先检查是否实例已经创建了,如果尚未 创建,"才"进行同步。这样一来,只有第一次会同步。 /** * 单列模式需要满足下面三个条件: * 1.私有的构造函数 * 2.私有的引用变量 * 3.公开的静态方法(唯一获取该类单个实例的地方) * * @author Administrator */ public class AmericaPresident { private volatile static AmericaPresident thePresident; /** * 功能:私有的构造函数 */ private AmericaPresident() { } /** * 功能:返回AmericaPresident对象 * @return */ public static synchronized AmericaPresident getPresident() { if(thePresident == null)//检查实例,如果不存在,就进入同步区块 { synchronized(AmericaPresident.class)//注意,只有第一次才彻底执行这里的代码 { if(thePresident == null)//进入区块后,再检查一次,如果还是Null,才创建实例。 { thePresident = new AmericaPresident(); } } } return thePresident; } } volatile关键字确保:当thePresident变量被初始化成AmericaPresident实例时,多个线程正确 处理thePresident变量。 如果性能是你关注的重点,那么这个做法可以帮你大大地减少getPresident()的时间消耗。