单例模式

概念:是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类

作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

优点:单列模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源,如读取配置,产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留在内存的方式来解决。

一>>单例模式实现方式

主要是以下五种:

主要:

1.懒汉式(线程安全,调用效率不高,但可以延时加载)

2.饿汉式(线程安全,调用效率高,但不可以延时加载)

其他:

3.双重检测锁式(由于jvm底层内部模型原因,偶尔会出现问题,不建议使用)

4.静态内部类式(线程安全,调用效率高,但是可以延时加载)

5.枚举单例(线程安全,调用效率高,不能延时加载,并且天然的防止反射和反序列漏洞)

①饿汉式

代码:

public class SingletonDemo {
//类初始化立即加载这个对象
private static SingletonDemo s = new SingletonDemo();

private SingletonDemo() {

};

public static SingletonDemo getInstance() {
return s;
}
}

懒汉式

代码:

public class SingletonDemo2 {
// 私有静态对象,加载时候不做初始化
private static SingletonDemo2 s = null;

// 私有构造方法,避免外部创建实例
private SingletonDemo2() {

};

public static SingletonDemo2 getInstance() {
if (s == null) {

s = new SingletonDemo2();
}
return s;
}
}

③静态内部类

代码:

public class SingletonDemo3 {
private static class SingletonClassInstance {
// static final 保证了内存中只有这样一个实例存在,而且只能被赋值一次,从而保证了线程安全性
private static final SingletonDemo3 s = new SingletonDemo3();
}

// 只有真正调用getInstance()才会加载静态内部类,加载类时是线程安全的
public static SingletonDemo3 getInstance() {
return SingletonClassInstance.s;
}

private SingletonDemo3() {

}
}

④枚举单例

代码:

*优点:实现简单 枚举本身就是单例模式,由JVM从根本上提供保障,避免通过反射和反序列化的漏洞
*缺点:无延迟加载
*/
public enum SingletonDemo4 {
/*
* 定义一个枚举的元素,他就代表了singleton的一个实例
*/
INSTANCE;
/*
* 单例可以有自己的操作
*/
public void singletonOperation() {
// 功能处理
}

}

注:双重检测锁式偶尔会出现问题,不建议使用,代码就不放了。

二>>各实现方式对比

单例对象占用资源少,不需要延时加载

枚举式好于饿汉式

单例对象占用资源大,需要延时加载

静态内部类式好于懒汉式

三>>如何防止单例模式的反射漏洞(主要针对是懒汉和饿汉式)

只需要在私有化构造器中添加判断

private SingletonDemo() {

  if(s != null){

  throw new RuntimeException();

  }

};

四>>如果防止单例模式的但序列话漏洞(主要针对是懒汉和饿汉式)

可以通过定义readResolve(防止获得不同对象),反序列化时,如果对象所在类定义了readResolve()那就定义返回哪个对象

具体就是在代码中加上如下代码

//反序列化时,如果定义了readResolve()则直接返回此方法指定的对象,而不需要单独在创建新对象。

private object readResolve() throws ObjectStreamException(){

  return s;

}

02-06 23:40