layout: post title: 设计模式-单列模式及原型模式 categories: [设计模式, java] description: 单例模式是非常经典的高频面试题,文章主要阐述单例模式的应用场景、IDEA 环境下的多线程调试方式、保证线程安全的单例模式策略、反射暴力攻击单例解决方案及原理分析、序列化破坏单例的原理及解决方案、常见的单例模式写法等方面来全面的解析单列模式的细节。 keywords: 单例, 设计模式
简介: 单例模式是非常经典的高频面试题,文章主要阐述单例模式的应用场景、IDEA 环境下的多线程调试方式、保证线程安全的单例模式策略、反射暴力攻击单例解决方案及原理分析、序列化破坏单例的原理及解决方案、常见的单例模式写法等方面来全面的解析单列模式的细节。
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 的调试功能来进一步的详细看看各个线程的执行情况
用线程模式调试,手动控制线程的执行顺序来跟踪内存的变化状态。先给线程内容打上断点:








本文由博客群发一文多发等运营工具平台 OpenWrite 发布