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

    整理一下设计模式的个人理解。

    描述

    单例模式是java中比较常见的一种设计模式,顾名思义为一个类只能创建一个实例,多用于全局对象,如:配置的加载,spring bean加载各种配置(spring容器所有bean默认都是单例)

    单例的特点为构造方法私有,因此必须内部进行实例化,并提供静态访问方法为其他对象提供该实例。即:

    1、单例只能有一个实例

    2、单例构造方法私有

    3、单例必须自己创建唯一实例,并提供其他对象访问该实例的静态方法

    优缺点

    • 优点:由于单例模式只生成了一个实例,所以能够节约系统资源,减少性能开销,提高系统效率,同时也能够严格控制客户对它的访问。
    • 缺点:因为系统中只有一个实例,这样就导致了单例类的职责过重,违背了“单一职责原则”,没有接口,不能继承,不方便扩展。

    实现

    1> 懒汉式-线程不安全

    public class Singleton1 {
    
        private static Singleton1 instance;
    
        /**
         * 构造方法私有
         */
        private Singleton1() {
    
        }
    
        /**
         * 提供静态访问实例方法
         * 懒加载,其他地方用到该实例时调用该方法/创建实例,多线程时可能会创建多个实例,线程不安全
         *
         * @return
         */
        public static Singleton1 getInstance() {
            if (instance == null) {
                instance = new Singleton1();
            }
            return instance;
        }
    
    }

    上述单例在多线程下会存在线程安全问题,比较直观的解决方案是直接在方法上加同步锁,以保证只会创建一个实例

    2> 懒汉式-线程安全(增加同步锁,多线程排队等待,会影响效率)

    public class Singleton2 {
    
        private static Singleton2 instance;
    
        /**
         * 构造方法私有
         */
        private Singleton2() {
    
        }
    
        /**
         * 提供静态访问实例方法
         * 懒加载,其他地方用到该实例时调用该方法/创建实例,增加同步锁,保证线程安全
         *
         * @return
         */
        public static synchronized Singleton2 getInstance() {
            if (instance == null) {
                instance = new Singleton2();
            }
            return instance;
        }
    
    }

    3> 饿汉式(类加载时创建,线程安全)

    类加载时即创建实例,后续直接获取该实例,好处为永远保持唯一线程安全,坏处为即使该实例永远也用不到也会创建,浪费内存资源。

    备注:考虑到规范,正常如果是永远不用的实例,就应该删除,所以一般也比较推荐使用饿汉式创建单例

    public class Singleton3 {
    
        // 直接实例化
        private static Singleton3 instance = new Singleton3();
    
        private Singleton3() {
    
        }
    
        /**
         * 直接返回已实例化的实例
         *
         * @return
         */
        public static Singleton3 getInstance() {
            return instance;
        }
    }

    4> 双重校验锁

    instance声明为volatile线程可见,以防止重排序造成线程不安全(重排序参考:https://blog.csdn.net/ym123456677/article/details/79700623)

    public class Singleton4 {
    
        // volatile 全局线程可见
        private volatile static Singleton4 instance;
    
        private Singleton4() {
    
        }
    
        /**
         * 获取实例  --  双重校验,先判断实例是否存在,不存在对类增加同步锁,保证只创建一次
         *
         * @return
         */
        public static Singleton4 getInstance() {
            if (instance == null) {
                synchronized (Singleton4.class) {
                    if (instance == null) {
                        instance = new Singleton4();
                    }
                }
            }
            return instance;
        }
    }

    5> 静态内部类(明确指定要实现懒加载时使用)

    public class Singleton5 {
    
        private static class inner {
            // 声明为final 不可变
            private static final Singleton5 INSTANCE = new Singleton5();
        }
    
        private Singleton5() {
    
        }
    
        /**
         * 获取实例 -- (懒加载)第一个线程进来时就创建实例,并赋值给final常量INSTANCE,后续任何线程调用该方法,直接获取INSTANCE
         *
         * @return
         */
        public static Singleton5 getInstance() {
            return inner.INSTANCE;
        }
    }

    6> 枚举

    枚举为单例的最佳实践

    public enum Singleton6 {
        RED,
        GREEN,
        BLACK
    }

    考虑到实际应用,单例一般情况下使用饿汉式,明确要求实现懒加载时使用静态内部类,不过在实际应用中,单独使用的单例都不多了,配置一般都是通过spring bean的方式配置config,枚举使用较多,对于确定的类型、状态等,直接使用枚举。

  • 相关阅读:
    Android 设置 grid 不滚动
    SpringMVC + myBatis + mySQL 全注解 事务配置
    Git学习日志
    linux 下安装maven
    Maven 搭建springMVC 报错 maven web.xml param element param-name is not allowed here
    Python 函数式编程 filter(),map() , reduce()......
    onpropertychange 实时监控input输入框事件实现
    php CI 框架 mysql 事务使用
    This function has none of DETERMINISTIC, NO SQL解决办法
    安装inotify-tools,用inotifywait命令监听文件或目录的访问信息
  • 原文地址:https://www.cnblogs.com/flysand/p/11671349.html
Copyright © 2011-2022 走看看