单例模式(Singleton)是java中一个比较常见的设计模式,单例对象主要是为了保证在一个JVM中,该对象只有一个实例存在。主要优点:java
(1) 减小一些大型对象的开销,减小内存的占用面试
(2) 省去了new操做,较少了GC的压力设计模式
(3) 保证了一些核心类只被建立一次,好比一些核心的调度类,一些主要的操做类只被建立一次。安全
单例模式最多见的两种实现模式:饿汉式,懒汉式,内部静态类实现,双重检验锁模式函数
1.饿汉式:在进行类加载时就建立好 (添加了synchronized保证了线程的安全性)优化
package designPatterns; public class SingletonHungry { private static SingletonHungry instance = new SingletonHungry(); //私有构造函数,防止被实例化 private SingletonHungry(){ } public static SingletonHungry getInstance(){ return instance; } }
2. 懒汉式:延迟加载,在用到的时候才进行建立spa
package designPatterns; public class SingletonLazy { private static SingletonLazy instance = null; //私有构造函数,防止被实例化 private SingletonLazy(){ } public static SingletonLazy getInstance(){ if(instance == null){ instance = new SingletonLazy(); } return instance; } }
固然懒汉模式是线程不安全的,为了保证线程安全,咱们能够将函数定义成synchronized的,可是实际上,并非每次都须要同步的,只是在第一次建立对象的时候须要确保同步,所以咱们能够只同步一个对象。以下线程
package designPatterns; public class SingletonLazy { private static SingletonLazy instance = null; //私有构造函数,防止被实例化 private SingletonLazy(){ } /* public static SingletonLazy getInstance(){ if(instance == null){ instance = new SingletonLazy(); } return instance; } */ public static SingletonLazy getInstance(){ if(instance == null){ synchronized(instance){ if(instance == null){ instance = new SingletonLazy(); } } } return instance; } }
可是,因为java中建立对象和赋值操做是分开进行的,也就是说instance = new SingletonLazy()这句话是分步执行的。JVM的即时编译存在指令重派的优化,2,3步的操做是没法肯定的。设计
1. 给instance分配内存code
2. 调用构造函数初始化成员变量
3. 将instance对象指向分配的内存空间(执行完这句话以后instance才会变成非null的)
两步执行的,可能先执行分配空间,再初始化,这也可能会致使A,B两个线程不一样步,因此还有一种方法是使用内部静态类来进行实现,内部静态类在另外一篇博客中有详细介绍,这里再也不赘述。
3. 静态内部类,代码以下:
package designPatterns; public class Singleton { //私有构造方法,防止被实例化 private Singleton(){ } //静态内部类建立实例 private static class SingletonFactory{ private static Singleton instance = new Singleton(); } //获取实例 public static Singleton getInstance(){ return SingletonFactory.instance; } //若是该对象被用于序列化,能够保证对象在序列化先后保持一致 public Object readResolve(){ return getInstance(); } }
使用内部静态类的方法,只有在外部类被调用时才会被加载,而后new一个实例,这样就避免了锁的应用,通常建议使用这种方法,但仍是须要根据实际须要来进行选择的。
4. 双重检验锁模式(虽然内部类的方法感受更加好用一些,可是不少面试官想让你写的仍是双检锁模式)
public class Singleton { private volatile static Singleton instance; //volatile的可见性 private Singleton() {} public static Singleton getSingleton() { if(instance == null) { //Single Check synchronized(Singleton.class) { if(instance == null) { //Double Check instance = new Singleton(); } } } return instance; } }
双检锁模式其实就是为了保证一个顺序。双检锁的出现保证了上述2,3句的执行顺序。