vlambda博客
学习文章列表

面试必问之单例模式!



单例模式:

所谓单例,就是整个程序有且只有一个实例。

该类负责创建自己的对象,同时要确保只有一个对象被创建,好处就是一个类你只能创建一个实例对象会节约内存开销,一般常用在工具类的实现


特点

.类构造器私有

.持有自己类型的属性

.对外提供获取实例的静态方法

面试必问之单例模式!

懒汉模式:

package day01;
/**
* 懒汉模式:延迟初始化,线程不安全,严格意义上说不是单例模式
* 单例模式获取实例的三个要素:
* 1.类构造器私有
* 2.持有自己类型的属性
* 3.对外提供获取实例的静态方法
* @author 直条纹先生
*
*/
public class Singleton {
//2.持有自己类型的属性
private static Singleton instance;
//1.类构造器私有
private Singleton(){}
//3.对外提供获取实例的静态方法
public static Singleton getInstance(){
if(instance==null){
instance = new Singleton();
}
return instance;

}


}
package day01;

public class Test {

public static void main(String[] args) {

Singleton single1 = Singleton.getInstance();
Singleton single2 = Singleton.getInstance();

//判断地址一致返回true,论证是同一个对象实例
System.out.println(single1==single2);




}

}



面试必问之单例模式!

饿汉模式:

线程安全,比较常用,但容易产生垃圾,因为一开始加载类的时候就初始化了实例



package day02;
/**
* 饿汉模式:一开始就初始化
* 比较消耗对象资源
* @author 直条纹先生
*
*/
public class Singleton {

//持有自己类型的属性
//static 静态修饰的属性在类加载的时候初始化,并只会加载一次

private static Singleton instance = new Singleton();

//类构造器私有
private Singleton(){}

//对外提供获取实例的静态方法
public static Singleton getInstance(){
return instance;

}

}

package day02;
public class Test {

public static void main(String[] args) {

Singleton single1 = Singleton.getInstance();
Singleton single2 = Singleton.getInstance();

//判断地址一致返回true,论证是同一个对象实例
System.out.println(single1==single2);




}

}






面试必问之单例模式!

双检测锁模式实现单例:

双检锁模式也叫双重校验锁,综合了懒汉模式和饿汉模式两者的优缺点整合而成。


public class Singleton{
   
   //volatile
   private static volatile Singleton instance;
   
   private Singleton(){}
   
   public static Singleton getInstance(){
       
       if(instance==null){
           Synchronized(Singleton.class){
               if(instance==null){
                   instance=new Singleton();
              }  
          }
      }
       return instance;
  }  
}
双重锁模式,进行两次判断,第一次判断是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。
由于Singleton instance()对象在创建的时候jvm中可能会重新排序,在多线程访问下存在风险。使用volite修饰
instance实例操作不会被jvm重排序。解决该问题    


内部类模式实现单例:

public class Singleton{
   
   private Singleton(){}
   
   public static Singleton getInstance(){
       return Inner.instance;
  }
   
   //内部类
   public static class Inner{
       
       private static final Singleton instance = new Singleton();
       
  }
   
   
}





只有第一次调用getInstance()方法时,虚拟机才加载Inner并初始化instance,
只有一个线程可以获得对象的初始化锁,其他线程无法进行初始化,保证对象的唯一性。【目前此方式是所有单例模式中最值得推荐的一种方式】



通过枚举实现单例:(基本不用)



package day05;

/**
*
* 默认枚举实例的创建是线程安全的,并且在任何情况下都是单例。实际上
* 枚举类隐藏了私有的构造器。
* 枚举类的域是相应类型的一个实例对象
* 那么枚举类型日常用例是这样子的:
* @author 直条纹先生
*
*/

public enum Singleton {

Instance;
//doSomething 该实例支持的行为

//可以省略此方法,通过Singleton.INSTANCE进行操作

public static Singleton getInstance(){
return Singleton.Instance;

}


}