博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式——单例模式
阅读量:6261 次
发布时间:2019-06-22

本文共 4052 字,大约阅读时间需要 13 分钟。

单例模式

一、什么是单例模式:

单例模式是一种对象创建形模式,使用单例模式,可以保证为一个类只生成唯一的实例对象。也就是说,在整个程序空间中,该类只存在一个实例对象。

其实,GoF对单例模式的定义是:保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

二、为什么要使用单例模式:

在应用开发中,我们常常有以下 需求:

1、在多个线程之间,比如servlet环境,共享同一个资源或者操作同一个对象

2、在整个程序空间使用全局变量,共享资源

3、大规模系统中,为了性能的考虑,需要节省对象的创建时间等等。

因为Singleton模式可以保证为一个类只生成唯一的实例对象,所以这些情况,Singleton模式就派上用场了。

三、单例模式实现

1.饿汉式。

2.懒汉式。

3.双重检查。

四、实现

假如我们要得到一个对象的实例,通常是这么做的:
package com.meritit;public class Person {	private String name;	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}	}

package com.meritit;public class MainClass {	public static void main(String[] args) {		Person person1 = new Person();		Person person2 = new Person();		person1.setName("zhangsan");		person2.setName("lisi");				System.out.println(person1.getName());		System.out.println(person2.getName());	}}
要实现单例,必须私有化构造函数,你可能会想到这么实现单例:

package com.meritit;public class Person {	private String name;		/**	 * 私有化构造	 */	private Person(){			}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}		/**	 * 使用静态方法获得对象实例	 * @return	 */	public static Person getPerson(){		return new Person();	}	}
这样在每次使用该类的静态方法得到实例的时候都会创建一个新实例,这显然不是单例!,下面我们就用饿汉式来实现单例模式。

package com.meritit;public class Person {	//创建一个Person实例常量	private static final Person person = new Person();		private String name;		/**	 * 私有化构造	 */	private Person(){			}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}		/**	 * 使用静态方法获得对象实例	 * @return	 */	public static Person getPerson(){		return person;	}	}
上面这种就是饿汉式,下面我们再看一下怎么用懒汉式来实现:

package com.meritit;/** * 懒汉式单例模式 * @author Administrator * */public class Person {		private static Person person;		private String name;		/**	 * 私有化构造	 */	private Person(){			}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}		/**	 * 提供一个全局的静态方法	 * @return	 */	public static Person getPerson(){		//如果没有实例则创建实例		if(person == null){			person = new Person();		}		return person;	}	}
饿汉式在类加载的时候就创建了对象的实例,而懒汉式是在调用提供实例的静态方法时才创建(延迟加载)。那么上面的懒汉式是否能保证只提供一个实例?答案是在单线程下是肯定的,但是在多线性下就不能保证了。

如何解决懒汉式在多线程下的问题呢,使用同步方法,请看下面代码:

package com.meritit;/** * 懒汉式单例模式 * @author Administrator * */public class Person {		private static Person person;		private String name;		/**	 * 私有化构造	 */	private Person(){			}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}		/**	 * 提供一个全局的静态方法,并使用同步方法	 * @return	 */	public static synchronized Person getPerson(){		//如果没有实例则创建实例		if(person == null){			person = new Person();		}		return person;	}	}
上面的方法虽然解决了懒汉式多线程下的单例模式,但是还不够好,因为我们只需要同步创建实例的语句,而不需要同步整个方法,当第一个线程进来后person==null然后创建实例、第二个线程进来后person!=null就不会创建实例。所以只需同步person = new Person().这样可以提高程序的运行效率。

package com.meritit;/** * 懒汉式单例模式 * @author Administrator * */public class Person {		private static Person person;		private String name;		/**	 * 私有化构造	 */	private Person(){			}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}		/**	 * 提供一个全局的静态方法,并使用同步方法	 * @return	 */	public static Person getPerson(){		//如果没有实例则创建实例		if(person == null){			synchronized(Person.class){				person = new Person();			}		}		return person;	}	}
这样做就没有问题了吗?答案是“no"

当第一个线程执行到person==null后进入同步块,执行person=new Person()的时候第二个线程判断person==null,这时候当第一个线程执行完new Person()后第二个线程紧接着会执行new Person().

怎么解决这个问题呢?要效率还是要安全?????

齐声说“都要!!!!!”

我们发现这样做只所以能够提供效率是因为if(){ }中的语句只会被执行一次,那么我们为何不再给加个判断呢?

package com.meritit;/** * 懒汉式单例模式 * @author Administrator * */public class Person {		private static Person person;		private String name;		/**	 * 私有化构造	 */	private Person(){			}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}		/**	 * 提供一个全局的静态方法,并使用同步方法	 * @return	 */	public static Person getPerson(){		//如果没有实例则创建实例		if(person == null){			synchronized(Person.class){				//双重判断				if(person == null){					person = new Person();				}			}		}		return person;	}	}
这就是所谓的双重检查.

源代码下载:

转载于:https://www.cnblogs.com/lanzhi/p/6469843.html

你可能感兴趣的文章
jsp页面组成
查看>>
LCS记录
查看>>
C++开源跨平台类库集
查看>>
everything搜索工具小技巧
查看>>
一个 Sql语句优化的问题- STATISTICS 统计信息
查看>>
你不知道的KVO的内部实现
查看>>
转】MyEclipse10安装Log4E插件
查看>>
windows server2012r2 安装NET Framework 3.5
查看>>
[osg][osgEarth][原]基于OE自定义自由飞行漫游器(初级版)
查看>>
Java遇见HTML——JSP篇之JSP基础语法
查看>>
导出一个数据库中的表中的某一条数据
查看>>
JQuery初体验
查看>>
全球顶级黑客对决AI GeekPwn2017黑客大赛看点全面曝光
查看>>
浅析前端开发中的 MVC/MVP/MVVM 模式
查看>>
toString、equals和hashCode重写
查看>>
sizeof 和strlen的区别
查看>>
Python与C++引用分析
查看>>
误删一个用户 引起数据不准确问题
查看>>
一场失败的拔河比赛
查看>>
IOS开发工程师欢迎你加入宏略信息
查看>>