单例模式设计模式
作者:互联网
单例模式
单例模式必须具有三点
- 构造器私有化(只能自己访问)
- 提供一个私有的静态变量(static修饰 成为类变量,只能自己访问)
- 提供一个开放的方法 (访问变量)
常见的五种实现模式
主要
- 饿汉式(线程安全,调用效率高。不能延时加载)
- 懒汉式 (线程安全,调用效率不高,可以延时加载)
其他
- 双重检测锁式(由于JVM底层内部模型原因,偶尔出现问题,不建议使用,现在已经修复使用volatile 关键字 ,但不建议使用)
- 静态内部类式(线程安全,调用率高,可以延时加载)
- 枚举单例(线程安全,调用率高,不能延时加载)
饿汉式
public class SingletonDemo{
/*提供一个私有的静态变量*/
private static SingletonDemo singletonDemo=new SingletonDemo()
/*构造器私有化*/
private SingletonDemo(){}
/*提供一个开放的方法 */
public static /*synchronized*/ SingletonDemo getInstance(){
return singletonDemo; }
}
- 饿汉式单例模式代码中,static变量会在类转载时初始化,此时不会涉及多个线程对象访问的问题,虚拟机只会加载一次该类,不会发生并发问题,可以省略 synchronized关键字
- 问题:如果只是加载本类,而不是调用getInstance(),甚至没有调用,会造成资源浪费。
懒汉式
public class SingletonDemo{
private static SingletonDemo singletonDemo
private SingletonDemo(){}
public static synchronized SingletonDemo getInstance(){
if(null==singletonDemo){
singletonDemo=new SingletonDemo()
}
return singletonDemo;
}
}
双重检测单例模式
public class SingletonDemo{
/**必须加volatile 关键字 否则可能回去空对象
private volatile static SingletonDemo singletonDemo;
private SingletonDemo(){}
public static SingletonDemo getInstance(){
if(null==singletonDemo){
synchronized(SingletonDemo.class){
if(null==singletonDemo){
singletonDemo=new SingletonDemo ();
}
}
}
return singletonDemo;
}
}
静态内部类方式(推荐)
public class SingletonDemo{
private static SingletonClass (){
private static final SingletonDemo instance=new SingletonDemo ();
}
private SingletonDemo(){}
public static SingletonDemo getInstance(){
return SingletonClass.instance;
}
}
- 外部类没有static属性,不会立即加载对象
- 只有调用getInstance(),才会加载静态内部类。加载类天然是线程安全的,instance是static修饰的,保证内存中只有一个实例存在,而且只能赋值一次
- 兼备了并发高效调用,延迟加载的优势
枚举单例模式
public enum SingletonDemo{
/**枚举本身就是单例的
INSTANCE;
//添加业务操作
public void method(){
}
}
- 枚举本身就是单例的,但是枚举没有延迟加载,其余都好。
选用:
占用资源少,不需要延迟加载:
- 枚举式 好于 饿汉式
占用资源大,需要延时加载: - 静态内部类 好于 懒汉式
反射和反序列化可以破解以上的除了枚举 的其他单例模式(枚举基于jvm底层实现的天然单例)
破解方式(以懒汉模式为例)
反射破解
Class<SingletonDemo> clazz =(Class<SingletonDemo>) Class.forName("com.**.SingletonDemo")
Constructor<SingletonDemo> c=clazz.getDeclaredControctor(null);
c.setAccesssible(true);
SingletonDemo s1=c.newInstance();
SingletonDemo s2=c.newInstance();
两个对象地址自不一样
反序列化破解
写
SingletonDemo s3=SingletonDemo.getInstance();
FIleOutputStream fos = new FileOutputStream("d:/a.txt")
ObjectOutputStream oos = new ObjectOutputStream (fos)
oos.writeObject(s1)
oos .close;
fos.close
读
ObejcetInputStream ois = new ObejcetInputStream (new FileInputStream ("d:/a.txt"))
SingletonDemo s4= (SingletonDemo) ois .readObject()
s3和s4的地址不同
防止破解
防止反射(在私有构造器加入判断如下)
private SingletonDemo(){
if(null != instance){
throw new RuntimeException();
}
}
防止序列化破解(在类里面加入一个方法)
/*反序列化时,如果定义了readResolve()则直接返回此方法返回的对象,而不需要单独再创建对象
private Object readResolve() throws ObjectStreamException{
return instance
}
常见的应用场景
- Windows的Task Manager(任务管理器)
- 数据库连接池一般采用单例模式
- 操作系统的文件系统一般单例模式
- Application也是单例的典型应用
- 在spring容器中,默认bean为单例,便于管理
- 在servlet编程中,每个servlet也是单例
- 在springMVC/Structs1框架中,控制器对象也是单例
标签:singletonDemo,设计模式,模式,static,private,单例,SingletonDemo,加载 来源: https://blog.csdn.net/weixin_43704975/article/details/97614163