设计模式的学习和部分应用源码分析(单例模式)

首先是饿汉式(非延迟加载单例类)

public class HungrySinglePatterns {

    /**
     * 类进行初始化的时候,就立即加载这个对象。没有延时加载的优势。加载类时,线程是安全的。
     */
    private static HungrySinglePatterns instance = new HungrySinglePatterns();

    private HungrySinglePatterns() {	}

    /**
     * 方法没有同步,调用率高
     */
    public static HungrySinglePatterns getInstance() {
        return instance;
    }
}

应用:待补充

2.懒汉式(同步延迟加载)

public class LazyLoadSinglePatterns {
    private static LazyLoadSinglePatterns instance;
    /**
     * 私有化构造器
     */
    private LazyLoadSinglePatterns() {	}

    /**
     * 因为是延时加载所以有可能出现线程同步的问题。所以要加上 同步块。
     * 如果A线程执行 方法。 instance为null的时候, B线程又要执行方法,那么这个时候,两个线程都判断instance为null
     * 就会创建出两个对象。 所以要加上synchronized。 导致调用效率不高。
     * @return
     */
    public static synchronized LazyLoadSinglePatterns getInstance() {
        if (instance == null) {
            return new LazyLoadSinglePatterns();
        }
        return instance;
    }
}

应用:待补充

3.双重检测锁

  /**
     * 双重检测锁
     * 懒加载,调用率高。没有同步问题。但是因为jvm底层问题,容易出现问题,不推荐使用
     */
    public class DoubuCheckLockedSinglePatterns {
        private volatile static DoubuCheckLockedSinglePatterns instance = null;
        private DoubuCheckLockedSinglePatterns() {}
    
        public static DoubuCheckLockedSinglePatterns getInstance() {
            if (instance == null) {  // 1. 第一次检查
                synchronized (DoubuCheckLockedSinglePatterns.class) {  // 2
                    if (instance == null) {   // 3. 第二次检查
                        instance = new DoubuCheckLockedSinglePatterns();  // 4
                    }
                }
            }
            return instance;
        }
    }

双重检测锁定失败的问题并不归咎于 JVM 中的实现 bug,而是归咎于 Java 平台内存模型。内存模型允许所谓的“重排序”,这也是失败的一个主要原因。所以这里要加volatile才能成功。

我们假设有两个线程 a 和 b 调用 getInstance() 方法,假设 a 先走,一路走到 4 这一步,执行 instance = new Singleton() 这句代码。

instance = new Singleton() 这句代码首先会申请一段空间,然后将各个属性初始化为零值(0/null),执行构造方法中的属性赋值[1],将这个对象的引用赋值给 instance[2]。在这个过程中,[1] 和 [2] 可能会发生重排序。

此时,线程 b 刚刚进来执行到 1(看上面的代码块),就有可能会看到 instance 不为 null,然后线程 b 也就不会等待监视器锁,而是直接返回 instance。问题是这个 instance 可能还没执行完构造方法(线程 a 此时还在 4 这一步),所以线程 b 拿到的 instance 是不完整的,它里面的属性值可能是初始化的零值(0/false/null),而不是线程 a 在构造方法中指定的值。

应用:

/**
     * Return the (raw) singleton object registered under the given name.
     * <p>Checks already instantiated singletons and also allows for an early
     * reference to a currently created singleton (resolving a circular reference).
     * @param beanName the name of the bean to look for
     * @param allowEarlyReference whether early references should be created or not
     * @return the registered singleton object, or {@code null} if none found
     */
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null && allowEarlyReference) {
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }

Spring的依赖注入(包括lazy-init方式)都是发生在 AbstractBeanFactory 的 getBean 里。 getBean 的 doGetBean 方法调用 getSingleton 进行bean的创建。lazy-init方式(lazy-init=“true”),在用户向容器第一次索要bean时进行调用;非lazy-init方式(lazy-init=“false”),在容器初始化时候进行调用。
从上面代码可以看到,spring依赖注入时,使用了双重检测锁的单例模式。也许是现在的jvm不会有双重检测锁失败的问题了?并没有查到相关资料,希望有大佬补充。

4.静态内部类

/**
 * 静态内部类,实现懒加载单例模式
 * 线程安全,懒加载,并且实现了延时加载。调用效率高
 */
public class StaticInteriorSinglePatterns {

    private static class SingletonClassInstance{
        private static final StaticInteriorSinglePatterns instance = new StaticInteriorSinglePatterns();
    }
    
    private StaticInteriorSinglePatterns() {}

    public static StaticInteriorSinglePatterns getInstance() {
        return StaticInteriorSinglePatterns.SingletonClassInstance.instance;
    }
}

5.枚举类

这里我用了一个获取数据库连接的例子

public enum DataSourceEnum {
    /**
     * mysql的Connection
     */
    DATASOURCE();

    private Connection connection = null;
    private DataSourceEnum() {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            String url="jdbc:mysql://localhost/youDatabase?useUnicode=true&characterEncoding=utf-8";
            String user="root";
            String password="root";
            connection = DriverManager.getConnection(url,user,password);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public Connection getConnection() {
        return connection;
    }
}
1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑。 2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等 3) 如果你想写出规范、漂亮的程序,就花时间来学习设计模式吧 课程内容和目标 本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式 1) 内容包括: 设计模式七大原则(一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式) 2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。
本教程为授权出品教程 1) 优秀的程序应该是这样的:阅读时,感觉很优雅;新增功能时,感觉很轻松;运行时,感觉很快速,这就需要设计模式支撑 2) 设计模式包含了大量的编程思想,讲授和真正掌握并不容易,网上的设计模式课程不少,大多讲解的比较晦涩,没有真实的应用场景和框架源码支撑,学习后,只知其形,不知其神。就会造成这样结果: 知道各种设计模式,但是不知道怎么使用到真实项目。本课程针对上述问题,有针对性的进行了升级 (1) 授课方式采用 图解+框架源码分析的方式,让课程生动有趣好理解 (2) 系统全面的讲解了设计模式,包括 设计模式七大原则、UML类图-类的六大关系、23种设计模式及其分类,比如 模式的8种实现方式、工厂模式的3种实现方式、适配器模式的3种实现、代理模式的3种方式、深拷贝等 3) 如果你想写出规范、漂亮的程序,就花时间来学习设计模式吧 课程内容和目标 本课程是使用Java来讲解设计模式,考虑到设计模式比较抽象,授课采用 图解+框架源码分析的方式 1) 内容包括:设计模式七大原则(一职责、接口隔离、依赖倒转、里氏替换、开闭原则、迪米特法则、合成复用)、UML类图(类的依赖、泛化和实现、类的关联、聚合和组合) 23种设计模式包括:创建型模式模式(8种实现)、抽象工厂模式、原型模式、建造者模式、工厂模式。结构型模式:适配器模式(3种实现)、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式(3种实现)。行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)。 2) 学习目标:通过学习,学员能掌握主流设计模式,规范编程风格,提高优化程序结构和效率的能力。
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页