设计模式之单例模式

设计模式之单例模式

简介

单例模式(Singleton Pattern),是一种常用的软件设计模式。单例模式能够确保一个类在任何时候只有一个实例,并且由类自己管理这个单独的实例,避免其它类产生实例,如果需要访问这个实例,可以通过类提供的全局访问点获取。

这种类型的设计模式属于创建型模式(提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活)。

非线程安全单例模式

public class NonThreadSafe {

	private static NonThreadSafe instance;
	
	private NonThreadSafe() {}
	
	public static NonThreadSafe getInstance() {
		if (instance == null) {
			instance = new NonThreadSafe();
		}
		return instance;
	}
}
  1. 创建一个private static私有静态类变量instance:保证实例的唯一性,且不会被外部其他类直接调用进行操作。

  2. 将类的构造方法修饰为private:表示不会被外部其他类调用进而随意创建实例,保证创建实例在NonThreadSafe类中进行。

  3. public static的getInstance方法:提供外部类调用进而获取实例。先判断实例是否为null,为null则创建实例并返回;反之,则直接返回实例对象。

    在这种实现方式中,我们在需要用到这个实例的时候才会去创建一个实例,如果我们永远用不到这个实例,那么它就永远不会产生,这就是延迟实例化

    但是,上面的代码仅限于单线程场景,若存在多线程访问的情况,很可能会出现多个实例的情况。

线程安全但低效率单例模式

public class ThreadSafePoorEfficiency {
	private static ThreadSafePoorEfficiency instance;
	
	private ThreadSafePoorEfficiency() {}
	
	public static synchronized ThreadSafePoorEfficiency getInstance() {
		if (instance == null) {
			instance = new ThreadSafePoorEfficiency();
		}
		return instance;
	}
}
  • 将getInstance()方法用synchronized关键字修饰:使得每个线程在进入这个方法之前必须等待别的线程离开这个方法,这样就保证了不可能存在两个线程同时进入此方法的情况。

该方法属于延迟实例化的实现方式,由于创建实例对象的操作在整个应用中只会在第一次执行,之后,调用getInstance()方法时,只是单纯的返回实例对象而已,即:同步的需求只需要在第一次执行创建实例对象操作时需要,之后就不用了,但是getInstance()方法使用了synchronized关键字修饰,导致整个方法在每次调用时都会同步,这样不知不觉中就降低了程序的执行效率。

线程安全且高效率单例模式

public class ThreadSafeHighEfficiency {
	private static volatile ThreadSafeHighEfficiency instance;
	
	private ThreadSafeHighEfficiency() {}
	
	public static ThreadSafeHighEfficiency getInstance() {
		if (instance == null) {
			synchronized (ThreadSafeHighEfficiency.class) {
				if (instance == null) {
					instance = new ThreadSafeHighEfficiency();
				}
			}
		}
		return instance;
	}
}
  1. 类变量instance增加了修饰符volatile:常用于保证内存可见性和防止指令重排序,但并不保证操作的原子性。volatile是一种稍弱的同步机制,在访问volatile变量时不会执行加锁操作,也就不会执行线程阻塞,因此volatilei变量是一种比synchronized关键字更轻量级的同步机制,但不如synchronized安全。
  2. getInstance()方法:去掉方法修饰符synchronized,在方法里面使用synchronized块,进入方法后首先判断属性是否为空,如果为空的话就进入同步代码块,进入同步代码块后会再检查一次属性是否为空,如果仍然为空才会创建实例。

这种方法被称为双重检查加锁,属于延迟实例化的实现方式,其保证了程序中只存在一个实例,而且这种实现方式只在第一次的时候才彻底执行所有的代码,当实例创建出来后也不会进入同步代码块,大大减少了性能的耗费。

JVM加载时创建单例模式

public class JVMLoadSingleton {
	private static JVMLoadSingleton instance = new JVMLoadSingleton();
	
	private JVMLoadSingleton() {}
	
	public static JVMLoadSingleton getInstance() {
		return instance;
	}
}

该方法不属于延迟实例化的实现方式,该方法直接在JVM加载类时创建实例对象,对外部只提供获取实例的方法getInstance(),这样外部类调用getInstance()时,方法会直接返回实例对象即可。但是它是在加载类的时候就会创建这个实例,如果创建这个实例非常耗费资源,而程序执行过程中一直没有使用到它,那么将会造成很大的浪费。

参考链接

设计模式——单例模式

Java并发:volatile内存可见性和指令重排

最后,谢谢各位读者的耐心阅读,如有语句不通顺或者不准确的地方,还请指正!谢谢!(__)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值