zoukankan      html  css  js  c++  java
  • 单例模式

    官方定义

    所谓类的单例设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)

    举个最常见的例子,Sping中的bean默认都是单例模式,每个bean定义只生成一个对象实例,每次getBean请求获得的都是此实例。

    单例模式的八中写法

    • 饿汉式(静态常量)
    • 饿汉式(静态代码块)
    • 懒汉式(线程不安全)
    • 懒汉式(线程安全,同步方法)
    • 懒汉式(线程安全,同步代码块)
    • 双重检查
    • 静态内部类
    • 枚举方法

    验证法:

    package singletonpattern.hungrydemo;
    
    public class SingletonDemo {
        public static void main(String[] args) {
            Singleton instance =  Singleton.getInstance();
            Singleton instance1 =  Singleton.getInstance();
            System.out.println(instance == instance1);//true
            System.out.println(instance.hashCode());
            System.out.println(instance1.hashCode());
    
        }
    }
    

    饿汉式(静态常量)

    class Singleton {
    
        //一、构造器私有化,防止外部用构造器
        private Singleton() {
        }
    
        //二、类的内部创建对象 final static
        private static final Singleton singleton = new Singleton();
    
        //三、对外提供公共的静态方法,返回该类唯一的对象实例
        public static Singleton getInstance() {
            return singleton;
        }
    }
    

    写法分析

    • 优势:简单 避免多线程的同步问题
    • 劣势:没有实现懒加载的效果,内存的浪费

    饿汉式(静态代码块)

    class Singleton {
    
        //一、构造器私有化,防止外部用构造器
        private Singleton() {
        }
    
        //二、类的内部创建对象 final static
        private static final Singleton singleton;
        
        static {
             singleton = new Singleton();
        }
    
        //三、对外提供公共的静态方法,返回该类唯一的对象实例
        public static Singleton getInstance() {
            return singleton;
        }
    }
    

    写法分析

    • 优势:简单 避免多线程的同步问题
    • 劣势:没有实现懒加载的效果,内存的浪费

    懒汉式(线程不安全)

    class Singleton {
        // 构造器私有化
        private Singleton() {
        }
    
        //类的内部提供对象
        private static Singleton singleton;
    
        //对外提供公共方法的静态方法的时候,来判断
        public static Singleton getInstance() {
            if (singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
    }
    

    写法分析

    • 优势:起到了懒加载的效果,不会造成内存浪费
    • 劣势:线程不安全

    懒汉式(线程安全,同步方法)

    class Singleton {
        // 构造器私有化
        private Singleton() {
        }
    
        //类的内部提供对象
        private static Singleton singleton;
    
        //对外提供公共方法的静态方法的时候,来判断
        public static synchronized Singleton getInstance() {
            if (singleton == null) {
                singleton = new Singleton();
            }
            return singleton;
        }
    }
    

    懒汉式(线程安全,同步代码块)

    class Singleton {
        // 构造器私有化
        private Singleton() {
        }
    
        //类的内部提供对象
        private static Singleton singleton;
    
        //对外提供公共方法的静态方法的时候,来判断
        public static Singleton getInstance() {
            if (singleton == null) {
                synchronized (Singleton.class){
                    singleton = new Singleton();
                }
            }
            return singleton;
        }
    }
    

    不推荐的,解决不了的线程安全问题

    双重检查

    class Singleton {
        private Singleton() {
        }
        private static Singleton singleton;
        //加入双重检查机制
        public static Singleton getInstance() {
            if (singleton == null) {
                synchronized (Singleton.class) {
                    if (singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    }
    

    写法分析
    实际开发中推荐使用这种方法

    • 线程安全 解决了线程安全问题
    • 懒加载 不会造成内存的浪费
    • 效率很高

    可能出现的问题
    我们认为的new Singleton()操作

    1)分配内存地址M
    2)在内存M上初始化Singleton对象
    3)将M的地址赋值给instance变量

    JVM编译优化后(指令重排)可能new Singleton()操作

    1)分配内存空间M
    2)将M的地址赋值给instance变量
    3)在内存M上初始化Singleton对象

    image
    会有可能发生空指针异常
    解决的方式
    只需要一个关键字 volatile 来禁止指令重排

    class Singleton {
        private Singleton() {
        }
        private static volatile Singleton singleton;
        //加入双重检查机制
        public static  Singleton getInstance() {
            if (singleton == null) {
                synchronized (Singleton.class) {
                    if (singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
    }
    

    扩展-Volatile
    轻量级的同步机制(低配版)没有保证原子性
    三大特性?
    保证可见性
    其中一个线程修改了主内存变量的值,要写回主内存,并要及时通知其他内存可见
    没有保证原子性
    (没法)不能保证不可分割,完整,要么同时成功,要么同时失败
    禁止指令重排
    和底层内存屏障相关,避免多线程下出现指令乱序的情况

    静态内部类

    class Singleton {
        private Singleton() {
        }
    
        private static class SingletonInstance {
            public static final Singleton INSTANCE = new Singleton();
        }
    
        public static Singleton getInstance() {
            return SingletonInstance.INSTANCE;
        }
    }
    

    写法分析

    • 不会出现线程安全问题
    • JVM来帮我们保证线程的安全性
    • 利用静态内部类的特点

    枚举方法

    enum Singleton{
        INSTANCE;//属性
    }
    

    写法分析
    不仅可以避免线程安全问题 推荐大家使用

    注意事项

    1.单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
    2.当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是new

    单例模式的使用场景

    • 对于一些需要频繁创建销毁的对象
    • 重量级的对象
    • 经常使用
    • 工具类对象
    • 数据源
    • ...
    转载请注明出处:https://www.cnblogs.com/stu-jyj3621
  • 相关阅读:
    fastJson Gson对比及java序列化问题
    HashMap遍历时的性能对比
    FileChannel与ByteBuffer的使用示例
    spring boot中ConditionalOnClass为什么没有classNotFound类加载异常
    maven插件: shade, assembly
    spring容器中的beanName
    线程状态
    IDEA插件
    IDEA 工具使用指南
    方法调用:对象的传值与传引用
  • 原文地址:https://www.cnblogs.com/stu-jyj3621/p/14670375.html
Copyright © 2011-2022 走看看