单例模式

                (1)单例模式概念

                          就是在整个应用中保证只有一个类的实例存在,就像是java web中的application,也就是一个全局变量


                 (2)最简单实现:可能浪费资源

                           1.思路

                               能够想到最简单的实现就是将构造函数写成private的,从而保证不能实例化此类,然后在类中提供一个静态的实例并能返回给使用者。

                           2.代码

public class Singleton 
{
	private static Singleton instance = new Singleton();
	
	private Singleton()
	{}
	
	public static Singleton getInstance()
	{
		return instance;
	}
}
                           3.问题

                              无论这个类是否被使用,都会创建一个instance对象,如果这个创建过程很耗时、耗资源,比如创建10000个数据库连接,并且这个对象并不被使用,那么就造成了极大的浪费。

                 (3)懒加载实现

                           1.思路

                               将静态变量instance初始化为null,那么在getInstance的时候先判断instance是否为null,为null的时候再生成一个实例

                           2.代码

public class Singleton 
{
	private static Singleton instance = null;
	
	private Singleton()
	{}
	
	public static Singleton getInstance()
	{
		if(instance == null)
		{
			instance = new Singleton();
		}
		
		return instance;
	}
}

                           3.问题

                              在单线程情况下,该程序不会有什么问题。但是如果是多线程,那么可能就会有问题。

                              假设线程A调用getInstance方法,因为是第一次调用,A发现instance是null的,所以通过了if判断,在将要创建instance的时候,cpu发生时间片切换,线程B得到执行,B也调用getInstance,因为A实际上并没有生成实例,那么B也通过了if判断,然后生成了instance。B创建完成后,A又得到执行,由于A已经通过了if判断,所以A也会创建一个instance。这样线程A、B都会有一个各自的Singleton

                 (4)同步问题

                           1.思路

                               因为getInstance方法出现了同步问题,所以直接加锁就可以了

                           2.代码

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

                           3.问题

                              synchronized修饰的同步代码块可能比一般的代码要慢上几倍,所以如果存在多次getInstance()调用,那么性能问题就必须要考虑了。

                 (5)同步优化问题

                           1.思路

                               现在来分析一下是整个方法需要加锁,还是其中某些加锁就可以了。为什么要加锁呢?就是因为判断null的操作盒生成对象的操作分离了,所以如果这两个操作能够实现原子性,那么单例也就能够保证了。

                           2.代码

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

                           3.问题

                              synchronized写在if上虽然保证了单例,但是同样不能解决同步的性能问题,因为每次调用getInstance,还是会进入同步代码块判断。所以,如果事先先判断是否为null,再去进行同步操作,就能提高性能。

                           4.代码

public class Singleton 
{
	private static Singleton instance = null;
	
	private Singleton()
	{}
	
	public  static Singleton getInstance()
	{
		if(instance == null)
		{
			synchronized(Singleton.class)
			{
				if(instance == null)
				{
					instance = new Singleton();
				}
			}
		}
		
		return instance;
	}
}
                           5.问题

                              因为每个线程都会有自己对变量的副本,每个线程对变量的修改可能不会及时通知到其他线程,造成其他线程读到错误的数据。

                 (6)最终方案1

                           1.思路

                                一般的线程都会对共享变量保存一个副本(为了提高效率),但是如果一个线程对该变量改变了,但是另一个线程使用的还是自己的副本,那么就会出错。使用volatile关键字,告诉jvm,这个变量是随时可能修改的,所以每个线程就不要保存副本了,直接取主存的

                           2.代码

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

                 (7)最终方案2

                           1.思路

                              使用静态内部类,因为是静态的,所以只会初始化一次,那么在这里直接返回内部静态类中维护的单例成员就可以了

                           2.代码

public  class Singleton 
{
	private static class SingletonIns
	{
		private static Singleton instance = new Singleton();
	}
	
	private Singleton()
	{}
	
	public Singleton getInstance()
	{
		return SingletonIns.instance;
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值