什么是单例模式
单例模式是在程序中,一个类保证只有一个实例,并提供统一的访问入口。
为什么要用单例模式
节省内存 节省计算
如对象实例中的一样的,那就不用每次都创建一个对象
方便管理
- 因为单例提供一个统一的访问入口,不需要创建N多个对象,很多工具类都用了单例实现,如日志、字符串工具类
保证结果正确
- 比如统计网站的访问次数等等
单例的实现方式
饿汉式
- 程序启动的时候就会实例化
1 public class Singleton { 2
3 private static Singleton singleton = new Singleton(); 4
5 private Singleton(){} 6
7 public static Singleton getInstance(){ 8 return singleton; 9 } 10 }
饿汉静态代码块形势
1 public class Singleton {
2
3 private static Singleton singleton;
4 static {
5 singleton = new Singleton();
6 }
7 private Singleton(){}
8
9 public static Singleton getInstance(){
10 return singleton;
11 }
12 }
懒汉式
- 非线程安全的实现
1 public class Singleton { 2 3 private static Singleton singleton; 4 private Singleton(){} 5 6 public static Singleton getInstance(){ 7 if (singleton == null){ 8 return singleton = new Singleton(); 9 } 10 return singleton; 11 } 12 }
- 线程安全的实现,单性能低
1 public class Singleton { 2 3 private static Singleton singleton; 4 private Singleton(){} 5 6 public static synchronized Singleton getInstance(){ 7 if (singleton == null){ 8 return singleton = new Singleton(); 9 } 10 return singleton; 11 } 12 }
- 线程安全的实现,双重校验
- 注意:两个校验都必须加,如果第二个没有加校验,当两个线程都通过了第一个if校验,此时会有一个线程进入同步代码块,创建singleton实例,接着第二个线程也会进入同步代码块,并会在创建一个singleton。那么这样就破坏了单例。如果不加第一个if校验,那么所有的程序就会串行执行,影响执行效率。所以两个校验都必须存在
1 public class Singleton { 2 /**由于 return singleton = new Singleton(); 这行代码在JVM中会分为三步处理 3 * 1.给singleton分配内存空间 4 * 2.调用singleton的构造函数开初始化 5 * 3.将singleton对象指向分配的内存空间(这步执行了就singleton就不是null了) 6 * 7 * 由于CPU会对这三个步骤重排序,如果顺序是1 3 2,那么就可能出现singleton就不是空的,但并没有初始化singleton 8 * 这样第二个线程可能拿到的就是为初始化的singleton,所以使用volatile来修饰singleton,防止重排序的问题 9 */ 10 private static volatile Singleton singleton; 11 private Singleton(){} 12 13 public static Singleton getInstance(){ 14 if (singleton == null){ 15 synchronized (Singleton.class) { 16 if (singleton == null) { 17 return singleton = new Singleton(); 18 } 19 } 20 } 21 return singleton; 22 } 23 }
- 线程安全的实现,双重校验
- 懒汉之静态内部类的方式
- 这种方式能保证线程的安全线性,当Singleton被装载时,并不会立刻实例化静态内部类SingletonInstance,而是在需要时才会实例化
1 public class Singleton { 2
3 private static class SingletonInstance{ 4 private static final Singleton singleton = new Singleton(); 5 } 6 private Singleton(){} 7 8 public static Singleton getInstance(){ 9 return SingletonInstance.singleton; 10 } 11 }- 懒汉之静态内部类的方式
枚举实现单例
- 实现简单、线程安全、可以防止反序列化、反射的方式破坏单例模式,如果通过反序列化或反射的方式创建实例,会抛出异常。这种方式是最好的实现的方式
1 public enum Singleton{ 2 INSTANCE; 3 public void whateverMethod(){ 4 }
5 }