栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

饿汉式单例模式:

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对象时一个初始化完成后的
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/713229.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号