学习设计模式系列之——单例模式(Java)

单例模式是一种对象创建型模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。
 其实,GoF对单例模式的定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

在单例模式中,有三种实现方式:1、饿汉式;2、懒汉式;3、双重检查,下面我们分别来看这三种方式。

 

/**
 *
 * Person.java
 * sxt_Singleton
 * 2010-7-7 下午09:22:32
 */

/** 
 * 饿汉式单例模式
 * 线程永远是安全的
 * 在单线程和多线程中可以保持单例
 * 2010-7-7 下午09:22:32
 */
public class Person {
	
	public static final Person person=new Person();
	
	/**
	 * 姓名
	 */
	private String name;

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * private Constructor
	 * Person.java
	 * 2010-7-7 下午09:25:52
	 */
	private Person() {
	}
	
	/**
	 * 提供一个全局的静态方法
	 */
	public static Person getPerson(){
		return person;
	}
}


主类的访问是:
		/*
		 * 饿汉式
		 */
		Person per=Person.getPerson();
		Person per2=Person.getPerson();
		per.setName("xiao");
		per2.setName("dai");
		
		System.out.println(per.getName());
		System.out.println(per2.getName());

 上述的是饿汉式,接下来我们看懒汉式

/** 
 * 懒汉式单例模式
 * 不能保证多线程中保证单例
 * 2010-7-7 下午09:22:32
 */
public class Person2 {
	
	/**
	 * 姓名
	 */
	private String name;
	
	private static Person2 person;

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * private Constructor
	 * Person.java
	 * 2010-7-7 下午09:25:52
	 */
	private Person2() {
	}
	
	/**
	 * 提供一个全局的静态访问方法
	 */
	public static Person2 getPerson(){
		/*
		 * 当A线程运行到if(person==null)时,person为null,因此执行person= new Person2();
		 * 此时,B线程也正好执行到if(person==null),但A线程还没有产生Person2的实例
		 * 因此B线程又一次执行了person= new Person2()
		 */
		if(person==null){
			person= new Person2();
		}
		return person;
	}
}

  由于懒汉式不能保证线程的安全性,因为我们对其进行改造,改造过后的代码如下:

/** 
 * 对Person2进行改造之后的Person3
 * 2010-7-7 下午09:22:32
 */
public class Person3 {
	
	private static Person3 person;
	
	/**
	 * 姓名
	 */
	private String name;

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * private Constructor
	 * Person.java
	 * 2010-7-7 下午09:25:52
	 */
	private Person3() {
	}
	
	/**
	 * 加入同步关键字,解决Person2多线程访问的问题
	 * 对整个方法同步的时候,效率比较低,解决方法看Person4
	 * 对整个方法时行同步,那么if(person==null)每次都要执行
	 * 提供一个全局的静态方法
	 */
	public static synchronized Person3 getPerson(){
		if(person==null){
			person= new Person3();
		}
		return person;
	}
}

 在Person3中,我们加入了同步关键字,但是效率不高,经过我们的改造,产生了Person4,代码如下:

/** 
 * 双得检查单例模式
 * 在单线程和多线程中可以保持单例
 * 2010-7-7 下午09:22:32
 */
public class Person4 {
	
	private static Person4 person;
	
	/**
	 * 姓名
	 */
	private String name;

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * @param name the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}
	
	/**
	 * private Constructor
	 * Person.java
	 * 2010-7-7 下午09:25:52
	 */
	private Person4() {
	}
	
	/**
	 * 加入同步关键字,解决Person2多线程访问的问题
	 * 同步关键没有在方法级加,是因为考虑到效率问题
	 * 采用同步代码块,保证了if(person==null)里面的代码只运行一次
	 * 例如:当A线程执行到if(person==null),此时person为null,因为执行同步代码块中的代码
	 * 同时,B线程也执行到了if(person==null),而A还没有产生Person4的实例,因此也执行同步代码块中的代码
	 * A结束以后,B开始,可是,person已经产生,那么B线程就会再执行person=new Person4()
	 * 那么在接下来的线程,如C、D线程,判断if(person==null)时,person已经不在是null了
	 * 那么方法直接返回
	 * 所在相对于Person3中的代码来说效率高
	 * 提供一个全局的静态方法
	 */
	public static  Person4 getPerson(){
		if(person==null){
			/*
			 * 同步代码块只会执行一次
			 * 因此相对于Person3,效率比较高
			 */
			synchronized(Person4.class){
				if(person==null){
					person=new Person4();
				}
			}
		}
		return person;
	}
}

 至此,三种实现方式如下所述。

单例保证了一处程序内,只有一个实例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值