单例模式

饿汉式

 

public class Singleton{

   private static Singleton instance = new Singleton();

   private Singleton(){}

   public static Singleton getInstance(){

        return instance;
   }
}

恶汉式:不用等待直接返回对象,在类被加载的时候就把Singleton实例给创建出来了。

优点:实现简单,线程安全

缺点:不需要实例时也加载实例,浪费内存

懒汉式

public class Singleton{

    private static Singleton instance = null;

    private Singleton(){}

    public static Singleton getInstance(){
        
       if(instance == null) {instance = new Singleton();}
       
       return instance;
    }

}

懒汉式
       优点:相比饿汉式,懒汉式显得没那么“饿”,在真正需要的时候再去创建实例
       缺点:线程不安全。在并发获取实例的时候,可能会存在构建了多个实例的情况。 

懒汉式改进

public class Singleton{

    private static Singleton instance = null;

    private Singleton(){}

    public static synchronized Singleton getInstance(){

        if(instance == null) instance = new Singleton();
 
        return instance;

    }


}

懒汉式的线程安全方式,用了synchronized,多线程环境下效率不高。

恶汉变种

public class Singleton{

  private static Singleton instance = null;

  static{

    instance = new Singleton();

  }

  private Singleton(){}
  
  public static Singleton getInstance(){

    return instance;

  }
  
}

 

懒汉式,变种,线程安全。

静态内部类【推荐】

public class Singleton{

    public static class SingletonHolder{

         private final static Singleton instance = new Singleton();

    }
 
    private Singleton(){}

    public static final Singleton getInstance(){
    
      return SingletonHolder.instance;

    }

}

 

 静态内部类,使用枚举方式,线程安全。
 通过静态内部类的方式实现单例模式是线程安全的,同时静态内部类不会在Singleton类加载时就加载,而是在调用getInstance()方法时才进行加载,达到了懒加载的效果。
 似乎静态内部类看起来已经是最完美的方法了,其实不是,可能还存在反射攻击或者反序列化攻击。
 

 

双重校验锁【推荐】

 

public class Singleton{

    private volatile static Singleton instance = null;

    private Singleton(){}

    public static Singleton getInstance(){
    
         if(instance == null) { //1

              synchronized (Singleton.class){

                  if(instance == null){

                      instance = new Singleton();

                  }

              }
             
         }

         return  instance;

    }

}

关于两次判null:

 第一次判null,instance为null创建实例,不为null则直接返回;

 第二次判null,如果多个线程都运行到1处,而其中一个线程获得锁之后创建了对象,如果这里不判null,那么后来的其他线程会再次创建对象。

 为什么要加volatile?
 java内存模型中,在创建对象时分3步:1.为对象分配空间;2. 初始化对象;3.返回对象引用。不加volatile时,有可能2和3进行重排序,即先返回对象引用,然后初始化对象,这样多线程下可能出现返回半初始化的对象

枚举【推荐】

 

public enum Singleton{

   instance;
 
   public void whateverMethod(){}

}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值