java的设计模式 - 单例模式
2024-09-16 10:42:50
java 面试中单例模式基本都是必考的,下面记录一下
饿汉式
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
其实真心觉得没什么问题
private Singleton
来修饰可以防止创建多个实例- 没有延迟加载?这是需求不同好吗!有很多的需求是希望一开始就加载好的,不希望要用的时候再加载的,比如是
java.lang.Runtime
但面试的时候,你不能这样回答,面试官不开心的,你要回答
- 没有延迟加载
- 譬如 Singleton 实例的创建是依赖参数或者配置文件的,在 getInstance() 之前必须调用某个方法设置参数给它,是不能使用。(在构造函数上传参不行吗?,不考虑延迟加载)
懒汉模式
public class Singleton {
private volatile static Singleton instance; //声明成 volatile
private Singleton (){}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
你看加个延迟加载
- 要将 instance 声明个 volatile 好让在多线程的环境下可见
- 又要注意在多线程的情况下要主要加锁,因为会出现一个线程认为是空要构造对象,而另一个对象也认为是空要构造对象是情况
麻烦!!!
但也有应用场景的,在资源占用很多,又不常用的情况下,可以考虑用懒汉模式
懒汉式二式 —— 内部静态类
public class Singleton {
private final static class SingleHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return SingleHolder.INSTANCE;
}
}
因为这个是 JVM 保证其线性安全性的,而且会在加载的时候创建,又不依赖版本,所以以前会比较推荐。
致命的危险
其实上面的东东都有致命的危险!反射
上面按正常人类的做法是不会产生多个实例,如果会产生多个实例是说明上面的方式或多或少不够完美 ,比如反射
@Test
public void test() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Constructor<?> cls = Singleton.class.getDeclaredConstructor();
cls.setAccessible(true);
Singleton singleton = (Singleton) cls.newInstance();
assertNotEquals(singleton,Singleton.getInstance());//明显这两个对象是不一样的!!!
}
也就是说上面的方式面对复杂的序列化或者反射攻击,可能会出现问题!(当然要先实现 Serializable 接口)
比如:
@Test
public void test() throws ClassNotFoundException, IOException {
//序列化对象到文件
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("singleton"));
objectOutputStream.writeObject(Singleton.getInstance());
//从文件中读取对象
File file = new File("singleton");
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));
Singleton singleton = (Singleton) objectInputStream.readObject();
//判断是否是同一个对象
assertNotEquals(singleton,Singleton.getInstance());
}
当然也有应对序列化的方式。
就是在类中添加readResolve
函数,因为反序列化中,如果存在这个函数,序列化的结果就是这函数的值。
所以你在要序列化中的类添加这句就可以了。
private Object readResolve() {
return getInstance();
}
但面对反射就确实无力了。
最好的方式 - 枚举类
public enum SingletonEnum {
INSTANCE;
}
- 面对反射:jvm 直接禁止了通过反射构造枚举实例的行为!
- 面对序列化:jvm 对 enum 类的序列化,不是调用 writeObject、readObject 这些方法的。结果是就算是序列化后再反序列化,结果都是一样。
以上
最新文章
- [12]APUE:高级 I/O
- Linux进程间通信之信号量
- table总结insertRow、deleteRow
- mybatis04 根据用户名称模糊查询用户信息
- Oracle预估的基数算法
- 国外程序员收集整理的PHP资源大全
- 设置phpMyAdmin本地自动登陆
- 如何掌握并提高linux运维技能
- C语言数组操作和指针操作谁更高效
- adoop(四)HDFS集群详解
- python---自己实现双向链表常用功能
- mysql脚本手动修改成oracle脚本
- ext 的controller中的refs的使用方法
- php 使用str_replace替换关键词(兼容字符串,一维数组,多维数组)
- hdu3001Travelling
- weblogic为同一domain下的不同server添加不同参数
- 技术进阶:Kubernetes高级架构与应用状态部署
- Maven进行Mahout编程,使其兼容Hadoop2.2.0环境运行 (转)
- 【20181031T2】几串字符【数位DP思想+组合数】
- 前端性能优化:DocumentFragments或innerHTML取代复杂的元素注入
热门文章
- [Active Learning] Multi-Criteria-based Active Learning
- 我眼中的 Nginx(五):Nginx — 子请求设计之道
- asp.net core系列 55 IS4使用Identity密码保护API
- Group Convolution分组卷积,以及Depthwise Convolution和Global Depthwise Convolution
- java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)
- 通过 React Hooks 声明式地使用 setInterval
- 《OdooERP应用与开发基础》试读:第一章-Odoo概述
- Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮
- linux屏幕扩展、扩展屏幕的校准
- windows之如何把文件夹转换成iso文件