GOF23-单例模式

单例模式

一、核心作用:

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

二、单例模式的优点

     减小系统开销等,优化共享资源的访问。

三、常见的五种单例实现方式

  1. 饿汉式(线程安全,调用效率高,但是不能延时加载);
  2. 懒汉式(线程安全,调用效率不高。但是可以延时加载);
  3. 双重检测锁式(由于jvm底层内部模型原因,偶尔会出现问题);
  4. 静态内部类式(线程安全,调用效率高。可以延时加载);
  5. 枚举单例(线程安全,调用效率高,但不能延时加载);

四、具体实现

1、饿汉式
public class Singleton {
	
	//类初始化时,立即加载这个对象(没有延时加载的优势)。加载类时,天然的是线程安全的!
	private static Singleton instance = new Singleton();  
	//私有化构造器
	private Singleton(){
	}	
	//方法没有同步,调用效率高!
	public static Singleton  getInstance(){
		return instance;
	}
}

注:饿汉式不管后期会不会用到该类的实例,都会创建出来,如果后期没有用到会造成资源的浪费。

2、懒汉式
public class Singleton {
	
	//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)。
	private static Singleton instance;  
	
	private Singleton(){ //私有化构造器
	}
	
	//方法同步,调用效率低!
	public static  synchronized Singleton  getInstance(){
		if(instance==null){
			instance = new Singleton();
		}
		return instance;
	}
	
}
3、双重检测锁模式
public class Singleton { 

  private static Singleton instance = null; 

  public static Singleton getInstance() { 
    if (instance == null) { 
      Singleton sc; 
      synchronized (Singleton.class) { //双重检测锁,如果是单层,容易发生并发问题
        sc = instance; 
        if (sc == null) { 
          synchronized (Singleton.class) { 
            if(sc == null) { 
              sc = new Singleton(); 
            } 
          } 
          instance = sc; 
        } 
      } 
    } 
    return instance; 
  } 
  //私有化构造器
  private Singleton() { 

  } 
    
}

注:虽然这种方式可以实现延时加载,但是由于jvm底层内部模型原因和编译器优化(指令重排)原因,不建议使用该方式。

4、嵌套类(静态内部类)方式
public class Singleton {
	
	private static class SingletonClassInstance {
		private static final Singleton instance = new Singleton();
	}
	
	private Singleton(){
	}
	
	//方法没有同步,调用效率高!
	public static Singleton  getInstance(){
		return SingletonClassInstance.instance;
	}
	
}

这里原来笔者写的是静态内部类,容易和内部类搞混,进入了误区,更正一下:
定义在一个类内部的类,这个类叫做“嵌套类”。嵌套类又分为两种:static和非static。后者又被称为“内部类”。
嵌套类是其所在类的成员,static嵌套类不能访问所在类的非static的成员变量和方法,而内部类可以访问所在类的所有成员,即使成员被private修饰。
static嵌套类:因为其不能直接访问所在类的非static成员变量和方法,所有其必须通过绑定所在类的实例来进行访问。
内部类:可以访问所有的成员,内部类一般分为成员内部类、局部内部类、匿名内部类。

  • 局部内部类:定义在方法内部的类。它的作用域仅局限于方法内,和局部变量一样不能被修饰为private、public、protected、static,并且只能访问方法内部定义的final变量。
  • 匿名内部类:匿名内部类与局部类对于作用域内的变量享有相同的访问权限。具体可以参考:(后续放链接)

扯远了

5、枚举类
public enum Singleton {
	
	//这个枚举元素,本身就是单例对象
	INSTANCE;
	
	//添加自定义的操作
	public void singletonOperation(){
	}
		
}

五、值得注意的地方

以上除了枚举类的实现,其他的方式都能被反射或者序列化反序列化破解单例模式。
防止反射破解的方式有在类的构造函数中加入判断,如果当前类有实例就跳过或者报错(根据具体的业务需求);
防止序列化反序列化破解方式有在类中加入一下代码

    //在反序列化时,如果定义了readResolve()则直接返回此方法指定的对象。而不需要单独再创建新对象!
	private Object readResolve() throws ObjectStreamException {
		return instance;
	}

六、常用的场景

  1. 在项目中读取配置的类一般只有一个对象。
  2. 数据库的连接池设计一般也采用单例模式。
  3. 应用程序中的日志应用,一般也采用单例模式,一个实例去操作日志文件的读写等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值