设计模式笔记之单例模式

设计模式笔记之单例模式

前言

在一个系统中某些对象只需要一份实例,比方线程池、缓存、日志对象、某些资源文件对象等。这类对象如果有了多个实例就会带来许多问题,例如程序行为异常、资源使用过量、执行结果不一致等。

为了实现程序中的某个对象只有一份实例,常见的实现方式有定义全局变量、开发人员之间约定和单例模式等。

单例模式详解

概念

单例模式确保一个类只有一个实例,并提供一个全局访问点。

为了保证只有一个实例,必须把构造方法私有化不能随意创建对象,并且需要提供一个实例化对象的公共方法。具体的代码实现如下:

 

package cn.lzz.hf.single;

public class SingleCounter {
	private Long count;
	//静态实例变量
	private static SingleCounter singleCounter;
	private SingleCounter(){
		this.count=0L;
	}
	/**
	 * 获取实例
	 * @return
	 */
	public static SingleCounter getInstance(){
		if(null==singleCounter){
			singleCounter=new SingleCounter();
		}
		return singleCounter;
	}
	public void addAccount(){
		this.count++;
	}
	public Long getCount() {
		return count;
	}
	
}

这样如果需要得到实例必须getInstance方法调用获取不能随意创建实例,而且在程序的任何地方都能调用getInstance方法得到实例。

上文的代码只适用于单线程情况。如果有多个线程同时访问getInstance方法获取实例,那么就会存在线程之间获取的实例对象不一致的情况。例如第一个线程判断实例变量等于空需要创建一个新的实例对象,就在它刚刚准备创建对象时需要让出CPU等待;这时第二个线程同样判断实例变量等于空,所以创建了一个新的对象返回。当线程一再次执行又会创建一个新的实例,这时候两个线程得到的实例变量就会不一样。

为了解决单例模式多线程的问题,下面介绍两种常用的解决方式。

饿汉式

package cn.lzz.hf.single;

public class SingleCounter {
	private Long count;
	//静态实例变量
	private static SingleCounter singleCounter=new SingleCounter();
	private SingleCounter(){
		this.count=0L;
	}
	/**
	 * 获取实例
	 * @return
	 */
	public static SingleCounter getInstance(){
		return singleCounter;
	}
	public void addAccount(){
		this.count++;
	}
	public Long getCount() {
		return count;
	}
	
}

饿汉式在代码初始化时创建对象,这样保证只有一份实例,不会有多线程问题。但是如果创建该实例需要大量资源和时间,会影响程序启动效率。

懒汉式

package cn.lzz.hf.single;

public class SingleCounter {
	private Long count;
	//静态实例变量
	private static volatile SingleCounter singleCounter;
	private SingleCounter(){
		this.count=0L;
	}
	/**
	 * 获取实例
	 * @return
	 */
	public static SingleCounter getInstance(){
		if(null==singleCounter){
			synchronized (SingleCounter.class) {
				if(null==singleCounter){
					singleCounter=new SingleCounter();
				}
			}
			
		}
		return singleCounter;
	}
	public void addAccount(){
		this.count++;
	}
	public Long getCount() {
		return count;
	}
	
}

懒汉式在需要对象时候才实例化,用双重判断加锁的方式,先判断实例是否创建,如果实例没有创建,用synchronize关键字保证代码同步。在同步代码块中再一次判断是否已经创建实例变量。同时用volatile关键字修饰静态实例变量,保证多个线程得到的实例对象是同一份。

总结

多线程情况下单例模式的实现方式有很多种,在这就不一一介绍。不管使用那种方式都需要考虑性能和资源然后选择最优的解决方法。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值