单例模式

核心作用

  • 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点

常见应用场景

  • 任务管理器
  • 回收站
  • 网站的计数器
  • 日志的管理
  • 数据库连接池
  • 操作系统中的文件系统
  • Application (Servlet中)
  • Spring中,每个Bean默认是单例的
  • Servlet中每个Servlet是单例的
  • spring MVC框架/status框架中,控制器对象也是单例的

常见的五种单例模式实现方式

懒汉式(单例对象延迟加载)

public class SingletonDemo(){
    //类初始化时不加载这个对象(真正用的时候再加载)
    private static SingletonDemo instance; //私有化构造器
    private SingletonDemo(){}
    //方法同步,效率低
    public static synchronized SingletonDemo getInstance(){
        if(instance==null){
           instance = new SingletonDemo();
        }
        return instance;
    }
}

饿汉式(单例对象立即加载)

public class SingletonDemo(){
    //类初始化时立即加载这个类对象,加载类时,天然是线程安全的
    private static SingletonDemo instance = new SingletonDemo(); //类初始化时立即加载
    private SingletonDemo(){
    }
    //方法没有同步,调用效率高
    public static SingletonDemo getInstance(){
        return instance;
    }
}

双重检测锁(将同步内容下放到if内部)

  • 提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步创建了以后就没必要了
  • 问题 1 由于编译器优化原因和JVM底层内部模型原因偶尔会出问题,不建议使用。
public class SingletonDemo3 { 
  private static SingletonDemo3 instance = null;
  private SingletonDemo3() {} 
  public static SingletonDemo3 getInstance() { 
    if (instance == null) { 
      SingletonDemo3 sc; 
      synchronized (SingletonDemo3.class) { 
        sc = instance; 
        if (sc == null) { 
          synchronized (SingletonDemo3.class) { 
            if(sc == null) { 
              sc = new SingletonDemo3(); 
            } 
          } 
          instance = sc; 
        } 
      } 
    } 
    return instance; 
  }     
}

静态内部类(也是一种懒加载)

  • 外部类没有static属性,不会出现像懒加载那样立即加载
  • 只有真正调用getInstance()才会加载静态内部类。加载类时是线程安全的。instance是static final类型,保证了内存中只有这样的一个实例存在,而且只被赋值一次,从而保证了线程安全性
  • 兼备了并发高效调用和延迟加载的优势
public class SingletonDemo4 {   
 private static class SingletonClassInstance {
  private static final SingletonDemo4 instance = new SingletonDemo4();
 }  
 private SingletonDemo4(){} 
 //方法没有同步,调用效率高!
 public static SingletonDemo4 getInstance(){
  return SingletonClassInstance.instance;
 }  
}

枚举单例

  • 实现简单
  • 枚举本身就是单例模式,线程安全的,由JVM从根本上提供保障,避免通过反射和反序列化的漏洞
  • 无延迟加载
public enum SingletonDemo5 {
 //这个枚举元素,本身就是单例对象!
 INSTANCE;  
 //添加自己需要的操作!
 public void singletonOperation(){
 }
}
public static void main(String[] args){
    SingletonDemo5 sd1 = SingletonDemo5.INSTANCE;
    SingletonDemo5 sd2 = SingletonDemo5.INSTANCE;
    System.out.println(s1==s2);
}

单例模式的破解和反破解

public void reflect() throws Exception {
    SingletonDemo sd1 = SingletonDemo.getInstance();
    SingletonDemo sd2 = SingletonDemo.getInstance();
    System.out.println(sd1==sd2);
    /*反射方式破解单例*/
    Class<SingletonDemo> clzz = (Class<SingletonDemo>) Class.forName("ren.kanxue.designmode.SingletonDemo");
    Constructor<SingletonDemo> constructor = clzz.getDeclaredConstructor(null);//获得构造器
    constructor.setAccessible(true);//访问私有的构造需要跳过权限的检查
    SingletonDemo sd3 = constructor.newInstance();
    SingletonDemo sd4 = constructor.newInstance();
    System.out.println(sd3==sd4);//不同的对象
    /*序列化反序列化方式破解单例*/
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/a.txt"));
    oos.writeObject(sd1);
    oos.close();
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/a.txt"));
    SingletonDemo s5 = (SingletonDemo) ois.readObject();
    System.out.println(s5);
}
public class SingletonDemo implements Serializable {
    private static SingletonDemo instance;  
    private SingletonDemo(){ //私有化构造器
      //多次调用时抛出异常,防止反射
    if(instance!=null){
       throw new RuntimeException();
      }
     }
     //方法同步,调用效率低!
     public static synchronized SingletonDemo getInstance(){
      if(instance==null){
       instance = new SingletonDemo();
      }
      return instance;
     }

    //反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象!
     private Object readResolve() throws ObjectStreamException {
      return instance;
     }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值