单例解决了什么问题:为了节约系统资源,有时需要确保系统中某个类只有唯一一个实例,当这个唯一实例创建成功之后,我们无法再创建一个同类型的其他对象,所有的操作都只能基于这个唯一实例。为了确保对象的唯一性,我们可以通过单例模式来实现,这就是单例模式的动机所在。
单例的应用场景:一般是对于那些业务逻辑上限定不能多例只能单例的情况,例如:类似于计数器之类的存在,一般都需要使用一个实例来进行记录,若多例计数则会不准确。
饿汉式:
条件:
- 构造器私有化
- 本类对象作为本类的属性存在 用static 修饰保证只加载一次,不会重复创建对象
- 公共的静态的方法可以通过该方法拿到属性
优缺点:
优点:安全
缺点:可能会导致对象创建过早
1 package com.设计模式; 2 3 /** 4 * 饿汉式 5 */ 6 public class ObjectShow1 { 7 public static int i = 123; 8 //静态私有成员,类在加载初期完成初始化;同时带来加载过早的问题 9 private static ObjectShow1 objectShow1 = new ObjectShow1(); 10 11 private ObjectShow1() { 12 //私有构造函数,只能被列对象初始化 13 System.out.println(i); 14 } 15 16 //使用public对外开放获取本类对象 17 public static ObjectShow1 getObjectShow1() { 18 return objectShow1; 19 } 20 }
懒汉式:
条件:
- 构造器私有化
- 本类对象作为本类的属性存在 static 修饰 但是不进行初始化
- 公共的静态方法 并且判断是否给属性赋值
优缺点:
优点:对象总是被需要的时候才被创建 解决了可能加载时机过早的问题
缺点:在线程初期 线程不安全
1 package com.设计模式; 2 3 /** 4 * 懒汉式 5 */ 6 public class ObjectShow2 { 7 public static int i = 123; 8 //静态私有成员,不用构造器进行初始化 9 private static ObjectShow2 objectShow2 = null; 10 11 private ObjectShow2() { 12 //私有构造函数,只能被列对象初始化 13 System.out.println(i); 14 } 15 16 //使用public对外开放获取本类对象,只有调用方法才会进行初始化 17 public static ObjectShow2 getObjectShow2() { 18 if (objectShow2 == null) { 19 objectShow2 = new ObjectShow2(); 20 } 21 return objectShow2; 22 } 23 }
双重检索式:
条件:
1.构造器私有化
2.本类的对象作为奔雷的属性存在 static 修饰 但不进行初始化
3.公共的静态方法 并且判断是否给属性赋值
优缺点:
程序的前期 线程不安全
Synchronized 锁
Synchronized 代码块 要求同一时间只有一个线程进入代码块区域
因为jvm内存模型的原因 双重检索 也会有微小的可能发生问题
1 package com.设计模式; 2 3 /** 4 * 双重检索式 5 */ 6 public class ObjectShow3 { 7 public static int i = 123; 8 //静态私有成员,不用构造器进行初始化 9 private static ObjectShow3 objectShow3; 10 11 private ObjectShow3() { 12 //私有构造函数,只能被列对象初始化 13 System.out.println(i); 14 } 15 16 //使用public对外开放获取本类对象,只有调用方法才会进行初始化 17 public static ObjectShow3 getObjectShow3() { 18 if (objectShow3 == null) { 19 //同步块,线程安全的创建实例 20 synchronized (ObjectShow3.class) { 21 //再次检查实例是否存在,不在才创建 22 if (objectShow3 == null) 23 objectShow3 = new ObjectShow3(); 24 } 25 } 26 return objectShow3; 27 } 28 }
静态内部类式:
条件:
1.定义一个静态内部类
2.外部类构造器私有化
3.外部类的对象 作为内部类的属性存在 static 修饰 进行初始化
4.公共的静态方法
优缺点:
解决了,对象创建时机过早的问题
没有产生线程安全问题
1 package com.设计模式; 2 3 /** 4 * 静态内部类式 5 */ 6 public class ObjectShow4 { 7 public static int i = 123; 8 9 static class InitObjectShow { 10 private static ObjectShow4 os = new ObjectShow4(); 11 12 public static ObjectShow4 getObj() { 13 return os; 14 } 15 } 16 17 private ObjectShow4() { 18 System.out.println("ObjectShow4.ObjectShow4"); 19 } 20 21 public void show() { 22 System.out.println("ObjectShow4.show"); 23 } 24 }