单例模式

本文深入探讨单例模式的概念及其实现方式,包括饿汉模式、懒汉模式、改进的懒汉模式、双重检查模式及内部类形式,并分析各自的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      在某些情况下,我们需要让某个类在全局只有一个实例(比如用于资源管理或者存储全局配置信息的类),这种情况下,如果我们不限制该类的创建,那么任何时候都可以使用new来创建对象。因此,我们要让该类自己创建对象并为系统提供方法去获得该唯一的对象,这种模式成为单例模式。

      单例模式有许多种形式,下面列出几种常见的:

 

一、饿汉模式

      饿汉中的“饿”表示即使我还没使用该对象,我也创建好,等到需要的时候就返回这个对象。

/**
 * 饿汉模式
 * 先初始化单例变量,当使用的时候返回该变量
 */
class Singleton
{
	//开始便初始化Singleton对象
	private static Singleton singleton = new Singleton();
	
	//私有的构造方法,使外界不能生成该对象
	private Singleton()
	{
		//初始化代码
	}
	
	//静态方法,调用是返回该唯一的Singleton对象
	public static Singleton getSingleton()
	{
		return singleton;
	}
}

       这种形式的单例问题在于当我们引入了该类但是又没有使用的时候,类中的单例变量就浪费了内存空间。

 

 

二、懒汉模式

      相对于饿汉,懒汉在开始并不初始化单例变量,而是等到第一次使用的时候才去创建对象。

/**
 * 懒汉模式
 * 当使用的时候才初始化单例变量
 */
class Singleton
{
	//不初始化该变量
	private static Singleton singleton = null;
	
	//私有的构造方法,使外界不能生成该对象
	private Singleton()
	{
		//初始化代码
	}
	
	//静态方法,如果没有创建单例变量则创建并返回
	public Singleton getSingleton()
	{
		if(singleton == null)
		{
			singleton = new Singleton();
		}
		
		return singleton;
	}
}

      懒汉没有了饿汉的空间问题,但是,在多线程的情况下,当多个线程以及其接近的顺序逼近if(singleton == null),就有可能同时判断成功而去创建对象,因此该形式是类型不安全的。

 

三、改进的懒汉模式

      使用synchronized关键字能防止多个对象同时调用getSingleton()方法,解决同步问题:

/**
 * 改进的懒汉模式
 * 解决多线程的同步问题
 */
class Singleton
{
	//不初始化该变量
	private static Singleton singleton = null;
	
	//私有的构造方法,使外界不能生成该对象
	private Singleton()
	{
		//初始化代码
	}
	
	//静态方法,如果没有创建单例变量则创建并返回
	//同时是同步方法,同一时间只能一个对象访问
	public synchronized Singleton getSingleton()
	{
		if(singleton == null)
		{
			singleton = new Singleton();
		}
		
		return singleton;
	}
}

      这种情况防止了多个对象的创建,但是,我们需要同步的只是对对象的创建,而对象的返回是安全的,否则同意时间只能有一个外部对象能获得该单例的实例,影响了性能。


四、双重检查

      为了改进上述的性能问题,现在只对对象的创建进行同步:

/**
 * 只对对象创建执行同步
 * 这种情况依然会产生同步问题
 */
class Singleton
{
	//不初始化该变量
	private static Singleton singleton = null;
	
	//私有的构造方法,使外界不能生成该对象
	private Singleton()
	{
		//初始化代码
	}
	
	//静态方法,如果没有创建单例变量则创建并返回
	public Singleton getSingleton()
	{
		if(singleton == null)
		{
			//只同步对象的创建
			synchronized(Singleton.class)
			{
				singleton = new Singleton();
			}
		}
		
		//对象的返回不需同步
		return singleton;
	}
}
 

      这种形式依然会产生懒汉的线程同步问题,当多个线程同时通过if(singleton == null)的判断时,它们还是会依次创建单例实例,因此应该执行双重检查。

/**
 * 执行双重检查
 * 解决同步问题和性能问题
 */
class Singleton
{
	//不初始化该变量
	private static Singleton singleton = null;
	
	//私有的构造方法,使外界不能生成该对象
	private Singleton()
	{
		//初始化代码
	}
	
	//静态方法,如果没有创建单例变量则创建并返回
	public Singleton getSingleton()
	{
		//第一重检查
		if(singleton == null)
		{
			//同步对象的创建
			synchronized(Singleton.class)
			{
				//第二重检查
				if(singleton == null)
					singleton = new Singleton();
			}
		}
		
		//对象的返回不需同步
		return singleton;
	}
}
 

五、内部类形式

      此外,使用内部类也可以解决以上问题:

/**
 * 使用内部类的形式,没有同步和性能问题
 */
class Singleton
{
	//持有单例实例的内部类,但是不会立即初始化
	private static class SingletonContainer
	{
		//外部类可以访问内部类的私有成员
		private static Singleton singleton = new Singleton();
	}
	
	private Singleton()
	{
		//初始化代码
	}
	
	//静态方法,如果没有创建单例变量则创建并返回
	public Singleton getSingleton()
	{
		return  SingletonContainer.singleton;
	}
}
 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值