设计模式-单例模式

核心:

- 私有化构造器

- 创建静态属性或静态方法

- 保证一个类有且仅有一个实例,并提供一个访问他的全局访问点。

优点:

- 减小了系统开销。当一个对象的产生需要比较多的资源时(如读取配置、产生其他依赖对象),可以在应用启动时直接产生一个单例对象,永久驻留内存。

- 优化共享资源访问

五种单例实现方式:

  • 饿汉式(线程安全,调用效率高,不能延时加载)
  • 懒汉式(线程安全,调用效率不高,可以延时加载)
  • 双重监测锁式(由于jvm底层为了执行效率,会指令重排,可能会出问题,不建议使用)
  • 静态内部类式(线程安全,调用效率高,可以延时加载)
  • 枚举单例(线程安全,调用效率高,不能延时加载)

单例对象占用资源少,不需要延时加载,枚举好于饿汉式。

单例对象占用资源大,需要延时加载,静态内部类式好于懒汉式。

饿汉式:

public class Singleton01 {
	//类加载时直接创建该类的实例
	private static Singleton01 instance = new Singleton01();
	
	private Singleton01() {
	}
	
	public static Singleton01 getInstance() {
		return instance;
	}
}

由于jvm特性,加载类时是线程安全的,所以该方式是线程安全的。

在类加载时直接创建了类的实例,所以不能延时加载。

懒汉式:

public class Singleton02 {

	private static Singleton02 instance;
	
	private Singleton02() {
	}
	//加入了synchronized同步块,导致调用效率低
	public static synchronized Singleton02 getInstance() {
		if(instance!=null) {
			instance = new Singleton02();
		}
			
		return instance;
	}
}

可以在用的时候时候在创建实例,实现了懒加载,但是调用效率低。

双重监测锁式:

public class Singleton03 {
	private static Singleton03 instance;
	private Singleton03(){
	}
	public static Singleton03 getInstance() {
		if(instance == null) {
			Singleton03 sc;
			synchronized (Singleton03.class) {
				sc = instance;
				if(sc == null) {
					synchronized (Singleton03.class) {
						if(sc==null) {
							sc = new Singleton03();
						}
					}
					instance = sc;
				}
			}
		}
		return instance;
	}
}

静态内部类式:

public class Singleton04 {

	private Singleton04() {
	}
	
	public static Singleton04 getInstance() {			
		return SingletonHolder.instance;
	}
	//在使用的时候才会加载内部类
	private static class SingletonHolder{
		private static Singleton04 instance = new Singleton04();
	}
}

线程安全调用效率高,并且实现了懒加载

枚举:

public enum Singleton05{
    //枚举元素本身就是单例对象
    INSTANCE;
    
}

枚举模式避免了反射和反序列化的漏洞。

可以通过Singleton05.INSTANCE,直接获取到他的对象,枚举没有实现懒加载。

避免反序列化和反射创建新的对象(饿汉式为例):

1.避免反射创建新的对象

反射可以通过setAccessible(true)方式,访问被私有化的构造器。

为了避免这种情况发生可以在构造器中抛出一个异常(一般情况不会考虑)

public class Singleton01 {
	//类加载时直接创建该类的实例
	private static Singleton01 instance = new Singleton01();
	
	private Singleton01() {
        if(instance!=null){
            throw new RuntimeException();
        }
	}
	
	public static Singleton01 getInstance() {
		return instance;
	}
}

2.避免反序列化创建新的对象

只需要添加一个readResolve()方法就可以了,对象在反序列化时会先看有没有该方法,没有的话创建一个新的对象,但是有就会返回这个方法返回的对象

public class Singleton01 implements Serializable{
	//类加载时直接创建该类的实例
	private static Singleton01 instance = new Singleton01();
	
	private Singleton01() {
	}
	
	public static Singleton01 getInstance() {
		return instance;
	}
    
    private Object readResolve() throws ObjectStreamException{
        return instance;
    }
}

                                                                                                                                                                    感谢高淇java300集

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值