前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >多线程中单例模式的优化

多线程中单例模式的优化

作者头像
付威
发布2020-01-21 17:15:17
发布2020-01-21 17:15:17
71200
代码可运行
举报
运行总次数:0
代码可运行

单例模式

在编程中,单例模式是我们常用的一种设计模式,功能是保证在整个系统只用一个该对象的对象,具体代码如下:

代码语言:javascript
代码运行次数:0
运行
复制
public class Singleton {
	private static Singleton singleton;
	
	private Singleton() {
	}
	
	public static Singleton getInstance() {
		if (singleton == null) {
			singleton = new Singleton();
			return singleton;
		}
		return singleton;
	}
}

上面的代码我们知道并不是线程安全的,在多线程环境下,容易造成创建多个对象。 测试代码如下:

代码语言:javascript
代码运行次数:0
运行
复制
	@Test
	public void testSingleton() throws InterruptedException {
		for (int i=0;i<10;i++){
			new Thread(()->{
				Singleton.getInstance();
			}).start();
		}
		Thread.currentThread().join();
	}

运行结果如下:

代码语言:javascript
代码运行次数:0
运行
复制
创建对象
创建对象
创建对象
创建对象
创建对象
创建对象
创建对象

解决方案


对于上面的问题解决的方法有很多,比如使用加锁的方式,double检测的方式,为了验证最有方案我们把代码修改下:

代码语言:javascript
代码运行次数:0
运行
复制
public class Singleton {
	private   static Singleton singleton;
	
	private Singleton() {
		try {
			Thread.sleep(10);//增加创建对象的耗时
		} catch (Exception e) {
		
		}
	}
	
	public static Singleton getInstance() {
		synchronized (Singleton.class) {
			if (singleton == null) {
				singleton = new Singleton();
				return singleton;
			}
		}
		return singleton;
	}
}

测试代码

代码语言:javascript
代码运行次数:0
运行
复制
@Test
	public void testSingleton() throws InterruptedException {
		long start=System.currentTimeMillis();
		List<Thread> threadList = new ArrayList<>();
		for (int i = 0; i < 1000; i++) {
			Thread thread = new Thread(() -> {
				Singleton.getInstance();
			});
			threadList.add(thread);
			thread.start();
		}
		for (Thread t : threadList) {
			t.join();
		}
		long end=System.currentTimeMillis();
		System.out.println("运行耗时:"+(end-start));
	}
方案一:使用synchronized 关键字
代码语言:javascript
代码运行次数:0
运行
复制
public static Singleton getInstance() {
		synchronized (Singleton.class){
			if (singleton == null) {
				System.out.println("创建对象");
				singleton = new Singleton();
			}
		}
		return singleton;
	}

经过多次测试时间维持在410ms左右,下面是一次测试结果

代码语言:javascript
代码运行次数:0
运行
复制
运行耗时:410

这个虽然成功的保证了只有一个对象,但同样也会把其他的线程阻塞在创建的锁的前面,造成了性能上面的开销,如果创建一个对象的时间比较长,这个性能的开销是相当可观的。

方案二:double验证
代码语言:javascript
代码运行次数:0
运行
复制
	public static Singleton getInstance() {
		if (singleton == null) {
			synchronized (Singleton.class) {
				if (singleton == null) {
					singleton = new Singleton();
					return singleton;
				}
			}
		}
		return singleton;
	}
代码语言:javascript
代码运行次数:0
运行
复制
运行耗时:380

上面的代码虽然聪明的避开的过多线程等待的原因,但是彻底消除线程排队的现象,因为创建对象分需要耗时,这样就给其他线程提供了“可乘之机”

方案三:使用volatile共享变量 (最优方案)

共享变量是线程间同步的“轻量级锁”,彻底消除线程排队的现象,此处用于单例模式的设计,能够实现最小性能的开销:

代码语言:javascript
代码运行次数:0
运行
复制
private volatile static Singleton singleton;
代码语言:javascript
代码运行次数:0
运行
复制
运行耗时:280
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-02 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 单例模式
  • 解决方案
    • 方案一:使用synchronized 关键字
    • 方案二:double验证
    • 方案三:使用volatile共享变量 (最优方案)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档