设计模式-单例模式
1、单例模式的简介
定义:属于创建型模式,一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象
目标:保证一个类仅有一个实例,并提供一个访问它的全局访问点
解决问题:一个类被频繁的创建和销毁
说明:单例类只能有一个实例,必须自己创建自己的唯一实例,必须给所有其他对象提供这一实例
2、懒汉式,线程不安全
定义:最基本最简单的单例模式实现方式,使用实例的时候才会去初始化
优点:简单
缺点:线程不安全,不适合多线程
实现:
//单例类 public class lazyA { private static lazyA lazya; /** * 为了规范,添加空白的构造函数 */ public lazyA(){ } public static lazyA getName (){ if(lazya == null){ lazya = new lazyA(); System.out.println("This is a new lazyA"); }else{ System.out.println("This is exist a lazyA"); } return lazya; } public void show(){ System.out.println("How are you"); } } //测试方法 public static void main(String[] args) { lazyA lazyA1 = design.single.lazyA.getName(); lazyA1.show(); System.out.println("========================"); lazyA lazyA2 = design.single.lazyA.getName(); lazyA2.show(); System.out.println("========================"); System.out.println(lazyA1==lazyA2); } //测试结果 This is a new lazyA How are you ======================== This is exist a lazyA How are you ======================== true
3、懒汉式,线程安全
定义:最基本最简单的单例模式实现方式,使用实例的时候才会去初始化,能够在多线程中很好的工作,但是,效率很低,99% 情况下不需要同步
优点:第一次调用才初始化,避免内存浪费
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率
实现:
//单例类 public class lazyB { private static lazyB lazya; /** * 为了规范,添加空白的构造函数 */ public lazyB(){ } public static synchronized lazyB getName (){ if(lazya == null){ lazya = new lazyB(); System.out.println("This is a new lazyB"); }else{ System.out.println("This is exist a lazyB"); } return lazya; } public void show(){ System.out.println("How are you"); } } //测试方法 public static void main(String[] args) { lazyB lazyB1 = design.single.lazyB.getName(); lazyB1.show(); System.out.println("========================"); lazyB lazyB2 = design.single.lazyB.getName(); lazyB2.show(); System.out.println("========================"); System.out.println(lazyB1==lazyB2); } //测试结果 This is a new lazyB How are you ======================== This is exist a lazyB How are you ======================== true
4、饿汉式
定义:这种方式比较常用,但容易产生垃圾对象,类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了
优点:线程安全,没有锁,效率高
缺点:类加载时就初始化,浪费内存
实现:
//单例类 public class hungry { public static hungry hungry = new hungry(); private hungry(){ System.out.println("very hungry"); } public static hungry getHungry(){ System.out.println("me too"); return hungry; } public void show(){ System.out.println("hungry show"); } } //测试方法 public static void main(String[] args) { hungry hungry1 = design.single.hungry.getHungry(); hungry1.show(); System.out.println("==============================="); hungry hungry2 = design.single.hungry.getHungry(); hungry2.show(); System.out.println("========================"); System.out.println(hungry1==hungry2); } //测试结果 very hungry me too hungry show =============================== me too hungry show ======================== true
5、枚举
定义:这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法 它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化
优点:简单,容易实现,支持多线程
缺点:JDK1.5后加入的enum特性,不能通过 reflection attack 来调用私有构造方法
实现:
//单例类 public class enumTest { private enumTest() { } static enum singleEnum { //创建一个枚举对象,该对象为单例 SINGLE_ENUM; private enumTest enumTest; private singleEnum() { System.out.println("this is a enum"); enumTest = new enumTest(); } public enumTest getEnumTest(){ System.out.println("get enumEnum"); return enumTest; } } public static enumTest getInstance(){ System.out.println("this is a enumTest"); return singleEnum.SINGLE_ENUM.getEnumTest(); } } //测试方法 public static void main(String[] args) { enumTest enumTest1 = enumTest.getInstance(); System.out.println("========================"); enumTest enumTest2 = enumTest.getInstance(); System.out.println("========================"); System.out.println(enumTest1==enumTest2); } //测试结果 this is a enumTest this is a enum get enumEnum ======================== this is a enumTest get enumEnum ======================== true
6、双检锁(DCL)
定义:这种方式采用双锁机制,安全且在多线程情况下能保持高性能
优点:性能高
缺点:实现复杂
实现:
//单例类 public class Dcl { private static volatile Dcl dcl = null; private Dcl(){ } public static Dcl getDcl(){ System.out.println(dcl); System.out.println("one:"+(dcl == null)); if(dcl == null){ synchronized (Dcl.class) { if (dcl == null) { dcl = new Dcl(); } System.out.println("two:"+(dcl == null)); } } return dcl; } } //测试方法 public class Test { public static void main(String[] args) { Dcl dcl1 = Dcl.getDcl(); System.out.println("==============================="); Dcl dcl2 = Dcl.getDcl(); System.out.println("========================"); System.out.println(dcl1==dcl2); } } //测试结果 null one:true two:false =============================== design.single.Dcl@4554617c one:false ======================== true
7、静态内部类
定义:这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用
实现:
//单例类 public class StaticTest { private static final StaticTest STATIC_TEST = new StaticTest(); private StaticTest(){ System.out.println("one StaticTest"); } public static final StaticTest getStaticTest(){ System.out.println("two StaticTest"); return StaticTest.STATIC_TEST; } } //测试方法 public static void main(String[] args) { StaticTest staticTest1 = StaticTest.getStaticTest(); System.out.println("=============================="); StaticTest staticTest2 = StaticTest.getStaticTest(); System.out.println("=============================="); System.out.println(staticTest1==staticTest2); } //测试结果 one StaticTest two StaticTest ============================== two StaticTest ============================== true