单例模式的创建

Java知识点总结:想看的可以从这里进入

4.2.1 单例模式

类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例。Spring的IoC创建Bean对象时,默认的就是单例模式。

优点:防止其他对象对自己进行实例化,确保访问的都是一个实例,这样可以节约内存资源,提高系统性能,避免对共享资源的多重占用。

缺点:不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。单例模式没有抽象层,不能扩展,且职责过重,违背了单一性原则

应用场景:网站计数器、线程池、数据库连接池、任务管理器等等。

  1. 饿汉式,静态常量(可以使用)

    在类装载时完成了实例化,避免了线程同步问题,但是没有懒加载效果,可能会造成内存浪费

    public class Singleton {
        private Singleton() {	 //构造器私有化
        }
        //内部创建对象
        private final static Singleton instance = new Singleton();
        //提供静态方法返回对象
        public static Singleton getInstance(){
            return instance;
        } 
    }
    
  2. 懒汉式:等第一次使用的时候再初始化,即“懒加载”。

    1. 线程不安全(在单线程环境中适用)

      实际开发中不会使用,如果在多线程环境中,一个线程在执行 if 判断成功后还没有开始创建对象时,第二个线程也正好通过了 if 判断,这样就会产生两次实例化。

      public class Singleton {
          private static Singleton instance;		
          private Singleton(){		//构造器私有化
          }
          //在静态方法内创建对象,并返回,调用方法才会创建对象
          public static Singleton getInstance(){
              if (instance == null) {
                  instance = new Singleton();
              }
              return instance;
          }
      }
      
    2. 线程安全,同步方法(基本上从并行变成了串行,效率低,不推荐)(加在方法上,每次线程都会进行synchronized等待)

      public class Singleton {
          private static Singleton instance;		
          private Singleton(){		//构造器私有化
          }
          //在静态方法内创建对象,添加synchronized使线程安全
          public static  synchronized Singleton getInstance(){
              if (instance == null) {
                  instance = new Singleton();
              }
              return instance;
          }
      }
      
    3. 双重检查(推荐使用的)(针对1和2的情况,如果多个线程通过了第一次 if 的判断,但因为synchronized存在,后续等待的线程不会再重复实例化对象。而且,除了初始化的时候会加锁,后续的调用都是直接返回,解决了多余的性能消耗。)

      外层的 if 让后续的线程不再进行synchronized等待,而第二层 if 可以阻止多次实例化

      其中volatile是Java提供的一种轻量级的同步机制。Java 语言包含两种内在的同步机制:同步块 和 volatile 变量,相比于synchronized(重量级锁),volatile更轻量级,因为它不会引起线程上下文的切换和调度。而在变量上添加volatile,作用相当于一个内存屏障,所以才有了双检锁。

      public class Singleton {
      	//持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载(懒加载)
      	private static volatile Singleton instance = null;
      	//私有构造方法,防止被实例化 
      	private Singleton() {
               //判断对象是否创建,若创建则抛出异常。
               if(instance!=null){
                   throw new RuntimeException();
               }
       	}
      	//静态工程方法,创建实例并返回
      	public static Singleton getInstance() {
      		//synchronized关键字,加锁,可保证线程的安全性
      		if (instance == null) {  
      	          synchronized (Singleton.class) {  
      	              if (instance == null) {  		//双重检查,防止线程问题
      	            	  instance = new Singleton();  
      	              }  
      	          }  
      	      } 
      		return instance;
      	}
      }
      
  3. 静态内部类(推荐使用)

    public class Singleton {
        private Singleton(){ }
        //创建静态内部类,JVM只在第一次装载类时初始化,所以保证了线程的安全
        private static class SingletonInterior{
            private final static Singleton SINGLETON = new Singleton();
        }
        //在静态方法内创建对象,并返回,调用方法时装载SingletonInstance,创建对象
        public static  synchronized Singleton getInstance(){
            return SingletonInterior.SINGLETON;
        }
    }
    
  4. 枚举(《Effective JAVA》中大为推崇)

    可以避免多线程问题,还能防止反射或序列化重新创建新的对象,但相对的牺牲了静态工厂方法的优点,无法实现懒加载(本质上和饿汉模式相同,区别仅在于公有的静态成员变量)

    public enum Singletion{
        INSTANCE;		//一个属性保证了是单例
        ....属性方法....
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辰 羽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值