设计模式-单列模式及原型模式

简介: 单例模式是很是经典的高频面试题,文章主要阐述单例模式的应用场景、IDEA 环境下的多线程调试方式、保证线程安全的单例模式策略、反射暴力攻击单例解决方案及原理分析、序列化破坏单例的原理及解决方案、常见的单例模式写法等方面来全面的解析单列模式的细节。java

1. 单列模式

1.1 单列模式定义

  • 单例模式(Singleton Pattern)是指确保一个类在任何状况下都绝对只有一个实例,并提供一个全局访问点
  • 隐藏其全部的构造方法
  • 单例模式是建立型模式

1.2 适用场景

  • 确保任何状况下都绝对只有一个实例
  • ServletContext 、ServletContextConfig 等;在Spring 框架应用中ApplicationContext;数据库的链接池也都是单例形式。

1.3 单例模式常见的写法

单例模式主要包含如下几种写法:面试

  • 饿汉式单例
  • 懒汉式单例
  • 注册式单例
  • ThreadLocal单例

饿汉式单例

饿汉式单例是在类加载时候就马上初始化,而且建立单例对象,有着绝对的线程安全性,由于在线程还未出现以前就已经被建立了,因此不存在访问线程安全性 数据库

优势:安全

  • 没有加任何的锁、执行效率比较高,在用户体验上来讲,比懒汉式更好

缺点:微信

  • 类加载的时候就初始化,无论用与不用都占着空间,浪费了内存

代码实现:多线程

public class HungrySingleton {

    private HungrySingleton(){

    }

    private static HungrySingleton hungrySingleton = new HungrySingleton();

    public static HungrySingleton getHungrySingleton() {
        return hungrySingleton; 

    }

}

咱们也能够采用静态代码块来实现:框架

public class HungryStaticSingleton {

    private static final HungryStaticSingleton hungryStaticSingleton;

    static {
        hungryStaticSingleton = new HungryStaticSingleton(); 

    }

    private HungryStaticSingleton(){

    }

    public static HungryStaticSingleton getHungryStaticSingleton() {
        return hungryStaticSingleton; 

    }

}
上述两种写法都很是简单,饿汉式适用的场景通常是单例对象比较少的状况,在这基础上咱们下面看一下性能更优的写法。

懒汉式单例

被外部类调用的时候内部类才会加载,会出现线程安全问题 性能

代码实现: 测试

实现单例类 LazySimpleSingleton编码

public class LazySimpleSingleton {

    private LazySimpleSingleton(){}

    private static LazySimpleSingleton lazySimpleSingleton = null;

    public static LazySimpleSingleton getLazySimpleSingleton() {
        if (lazySimpleSingleton == null){
            lazySimpleSingleton = new LazySimpleSingleton(); 
        }
        return lazySimpleSingleton; 

    }

}

咱们编写线程测试类:

public class LazySimpleSingletonTest {

    public static void main(String[] args) {
        new Thread(()->{
            LazySimpleSingleton lazySimpleSingleton = LazySimpleSingleton.getLazySimpleSingleton(); 
            System.out.println(lazySimpleSingleton); 
        }).start(); 
        new Thread(()->{
            LazySimpleSingleton lazySimpleSingleton = LazySimpleSingleton.getLazySimpleSingleton(); 
            System.out.println(lazySimpleSingleton); 
        }).start(); 

    }

}

正常状况下输出的两个对象是相同的,也是单例, 可是会存在输出不一样的状况,也就是说出现线程安全问题,这里咱们用 IDEA 的调试功能来进一步的详细看看各个线程的执行状况

用线程模式调试,手动控制线程的执行顺序来跟踪内存的变化状态。先给线程内容打上断点:

线程内部打断点

线程0断点进入

线程0进入内部方法

切换线程1断点

线程1方法内部

线程1内部从新构建初始化

线程1从新构建初始化

两个线程返回的内容

本文由AnonyStar 发布,可转载但需声明原文出处。
仰慕「优雅编码的艺术」 坚信熟能生巧,努力改变人生
欢迎关注微信公帐号 :coder简码 获取更多优质文章
更多文章关注笔者博客 : IT简码
相关文章
相关标签/搜索