• 单例模式的创建


    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;
          } 
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    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;
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
      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;
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
      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;
        	}
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
    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;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    4. 枚举(《Effective JAVA》中大为推崇)

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

      public enum Singletion{
          INSTANCE;		//一个属性保证了是单例
          ....属性方法....
      }
      
      • 1
      • 2
      • 3
      • 4
  • 相关阅读:
    潘多拉 IOT 开发板学习(RT-Thread)—— 实验2 RGB LED 实验(学习笔记)
    项目实战:抽取中央控制器 DispatcherServlet
    基于Java的飞机大战游戏的设计与实现
    AI智能识别微信小程序源码带流量主功能
    人工智能安全-6-SQL注入检测
    Qt 样式设置
    大厂真题:【位运算】米哈游2023秋招-相加异或
    leetcode498. 对角线遍历
    设计模式-行为型-解释器模式
    20、架构-容器间网络
  • 原文地址:https://blog.csdn.net/yuandfeng/article/details/126559884