饿汉式单例、懒汉式单例和双重检查锁单例模式

饿汉式单例、懒汉式单例和双重检查锁单例模式,第1张

饿汉式单例、懒汉式单例和双重检查锁单例模式

饿汉式单例模式:

public class Hungry {

	private Hungry() {}
	private final static Hungry HUNGRY = new Hungry();
	
	public static Hungry getInstance() {
		return HUNGRY;
	}
}

懒汉式单例:

public class lazyMan {

	private lazyMan() {}
	private static lazyMan LAZY;
	
	public static lazyMan getInstance() {
		if(LAZY == null) {           //1:A线程执行
			LAZY = new lazyMan();	 //2:B线程执行
		}
		return LAZY;
	}
}

懒汉式单例模式的问题

首先声明一点——代码2这一行可以分解成:

    分配对象的内存空间初始化对象设置LAZY指向刚分配的内存地址

上边是我们任务的顺序,但是编译器可能对这一行代码优化成:

    分配对象的内存空间设置LAZY指向刚分配的内存地址初始化对象

假设A线程执行代码1的同时,B线程执行代码2,此时线程A可能会看到LAZY引用的对象还没有完成初始化,这肯定会出错;或者另一种情况,线程A和B同时执行到代码1,最终同时进入代码块new对象,返回了两个不同的对象;

解决方案

我们可以对getInstance()方法进行同步处理来解决这种问题:

public class lazyMan {

	private lazyMan() {}
	private static lazyMan LAZY;
	
	public synchronized static lazyMan getInstance() {
		if(LAZY == null) {
			LAZY = new lazyMan();
		}
		return LAZY;
	}
}

那么问题来了,我们都知道synchronized 是一个重量级锁,如果getInstance()方法被多个线程频繁调用,将会导致程序执行性能的下降。

解决方案(双重检查锁)

public class lazyMan {

	private lazyMan() {}
	private volatile static lazyMan LAZY;     //1
	
	public static lazyMan getInstance() {
		if(LAZY == null) {					 //2
			synchronized (lazyMan.class) {
				if(LAZY == null)
					LAZY = new lazyMan();
			}
		}
		return LAZY;
	}
}

如上面的代码:

    多个线程同一时间创建对象时,会通过加锁保证只有一个线程创建锁;如果检查LAZY不为空那么就不需要执行下面的加锁和初始化 *** 作,可以大幅的减少synchronized带来的性能开销。代码1处使用volatile
    修饰也很有必要,因为synchronized并不能禁止指令重排,使用volatile才能保证多线程情况下线程们看到的LAZY对象时一个初始化完成后的

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5709879.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-18
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存