【23种设计模式】P1 单例模式 (基于Java实现)

单例模式核心作用

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

  • 常见场景:
    (1)Windows的任务管理器和回收站,无论点击多少次都只有一个窗口
    (2)项目中,读取配置文件的类,一般也只有一个对象,没必要每次都去new对象读取
    (3)网站的计数器为了保证同步一般也会采用单例模式
    (4)数据库的连接池设计
    (5)Servlet编程中,每个Servlet也是单例的
    (6)在Spring中,每个Bean的默认就是单例的

优点

  • 由于只生成一个实例,减少了系统系能的开销
  • 单例模式可以在系统设置全局的访问点,优化共享资源访问
  • 单例模式可以说只要是一个合格的开发者都会写,但是如果要深究,小小的单例模式会牵扯到很多东西

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

  • 饿汉式(线程安全,调用效率高,不能延时加载)
  • 懒汉式(线程安全,调用效率不高,可以延时加载)
  • DCL懒汉式(由于JVM底层内部模型原因,偶尔会出现问题,不建议使用
  • 饿汉式改进:静态内部类式(线程安全,调用效率高,能延时加载)
  • 枚举单例(线程安全,调用效率高,不能延时加载)

代码实现

  • 饿汉式,即无论有没有用都先初始化,而这也会导致空间的浪费,那么我们就希望我们在调用到里面的getInstance()获取实例的时候,再去加载,即延时加载
    public class SingletonDemo01{
        //首先私有化构造器,让对象私有,保证只有一个对象,不可new
        private SingletonDemo01(){
        }
        //类在初始化的时候就加载对象
        private static SingletonDemo01 instance = new SingletonDemo01();
        //提供一个全局访问点,没有synchronized,效率更高
        public static SingletonDemo01 getInstance(){
            return instance;
        }
    }
    
  • 懒汉式,调用的时候才会去实例化
    public class SingletonDemo02{
        //首先私有化构造器,让对象私有,保证只有一个对象,不可new
        private SingletonDemo02(){
        }
        //类初始化的时候,不立即加载
        private static SingletonDemo02 instance;
        //提供一个全局访问点,synchronized使其成为同步方法,效率较低
        public static synchronized SingletonDemo02 getInstance(){
            if (instance == null){
                instance = new SingletonDemo02();
            }
            return instance;
        }
    }
    
  • DCL懒汉式,改进了synchronized,DCL即双重检测锁。如果线程刚进来的时候发现没有被创建,为空,就会去和其他线程竞争锁,当竞争得到锁之后,再去检查是否还为空,如果还为空就再去new一个,如果不为空就直接返回。
    public class SingletonDemo03{
        //首先私有化构造器,让对象私有,保证只有一个对象,不可new
        private SingletonDemo03(){
        }
        //类初始化的时候,不立即加载
        //volatile 保证有线程在对这个变量进行修改的时候,另一个线程中该变量的缓存就会失效
        //volatile 增加了指令的重排,避免第一个线程还没创建完成但第二个进程已经返回的问题
        //保证了原子性
        private volatile static SingletonDemo03 instance;
        //提供一个全局访问点,synchronized使其成为同步方法,效率较低
        public static SingletonDemo03 getInstance(){
            if (instance == null){
                synchronized(SingletonDemo03.class){
                	if(instance == null){
                		instance = new SingletonDemo03();
                	}
                }
            }
            return instance;
        }
    }
    
  • 饿汉式改进,使用静态内部类,外部类没有属性,只有当调用getInstance()的时候才加载静态内部类,加载的时候线程是安全的,final关键字保证了内存中只有一个实例存在,保证了并发情况下的高效率调用还可以延时加载
    public class SingletonDemo04{
        private SingletonDemo04(){
        }
    
        private static class InnerClass{
            private static final SingletonDemo04 instance = new SingletonDemo04();
        }
    
        public static SingletonDemo04 getInstance(){
            return InnerClass.instance;
        }
    }
    
    但是通过Java的反射机制可以破坏掉private,可以通过反射机制忽视掉权限检查,这样就能破坏掉private,就可以在外部new一个不同的
    img
  • 枚举式
    在这里插入图片描述
    可知,利用枚举,能很好的保证线程安全
    public enum SingletonDemo05 {
        INSTANCE;
    
        public SingletonDemo05 getInstance(){
            return INSTANCE;
        }
    }
    
发布了27 篇原创文章 · 获赞 12 · 访问量 5176

猜你喜欢

转载自blog.csdn.net/Kobe_k/article/details/104341799