设计模式(4) -- 单例模式(Singleton)
设计模式(4) -- 单例模式(Singleton)
试想一个读取配置文件的需求,创建完读取类后通过New一个类的实例来读取配置文件的内容,在系统运行期间,系统中会存在很多个该类的实例对象,也就是说系统中会同时存在多份配置文件的内容,这样会严重浪费内存资源。这样需要实现:在一个系统运行期间,只要一个类实例就可以了。
单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
现在一个类能够被创建多个实例,问题的根源在于类的构造方法是公开的,也就是可以让类的外部通过构造方法创建多个实例。换句话说,只要类的构造方法能让类的外部访问,就没有办法去控制外部来创建这个类的实例个数。
要想控制一个类只被创建一个实例,那么首要的问题就是要把创建实例的权限收回来,让类自身来负责自己类实例的创建工作,然后由这个类来提供外部可以访问这个类实例的方法,这就是单例模式的实现方式。
在Java中,单例模式分为两种,懒汉式和饿汉式。
懒汉式:
public classSingletonLan {
privatestaticSingletonLan uniqueInstance = null;
privateSingletonLan(){
}
publicstaticsynchronizedSingletonLan getInstance(){
if(uniqueInstance==null){
uniqueInstance = new SingletonLan();
}
return uniqueInstance;
}
publicvoidsingletonOPeration(){
}
privateString singletonData;
publicStringgetSingletonData(){
return singletonData;
}
}
饿汉式:
public classSingletonE {
private static SingletonE uniqueInstance= newSingletonE();
privateSingletonE(){
}
publicstaticSingletonEgetInstance(){
return uniqueInstance;
}
publicvoidsingletonOPeration(){
}
privateString singletonData;
publicString getSingletonData(){
return singletonData;
}
}
Java里面实现的单例是一个虚拟机范围。因为装载类的功能是虚拟机的,所以一个虚拟机在通过自己的ClassLoader装载饿汉式实现单例类的时候就会创建一个类的实例。这就意味着如果一个虚拟机里面有很多个ClassLoader,而且这些ClassLoader都装载某个类的话,就算这个类是单例,它也会产生很多个实例。当然,如果一个机器上有多个虚拟机,那么每个虚拟机里面都应该至少有一个这个类的实例,也就是说整个机器上就有很多个实例,更不会是单例了。
单例模式的精粹是static变量在类装载的时候进行初始化;多个实例的static变量会共享同一块内存区域。
单例模式有一种应用叫延迟加载(Lazy Load):一开始不需要加载资源或者数据,一直等,等到马上要使用这个资源或者数据的时候才去加载。
利用缓存来实现单例模式:
import java.util.HashMap;
import java.util.Map;
public classSingletonCache {
private final static String DEFAULT_KEY="One";
private static Map<Object,SingletonCache> map = newHashMap<Object,SingletonCache>();
private SingletonCache(){
}
public static SingletonCache getInstance(){
SingletonCache instance = (SingletonCache)map.get(DEFAULT_KEY);
if(instance==null){
instance = new SingletonCache();
map.put(DEFAULT_KEY,instance);
}
return instance;
}
}
从线程安全上讲,懒汉式是线程不安全的,饿汉式是线程安全的(虚拟机保证只会加载一次,在装载类的时候是不会发生并发的),但是加了synchronized关键字的懒汉式是线程安全的,只是效率下降了。
可以使用双重检查加锁机制,指的是并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了。
双重检查加锁机制的实现用到关键字volatile,意思是被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。由于volatile关键字可能会屏蔽虚拟机中一些必要的代码优化,所以运行效率并不是很高。
public classSingletonVolatile {
privatevolatilestaticSingletonVolatile instance = null;
privateSingletonVolatile(){
}
publicstaticSingletonVolatilegetInstance(){
if(instance== null){
synchronized(SingletonVolatile.class){
if(instance==null){
instance = newSingletonVolatile();
}
}
}
return instance;
}
}
Lazyinitialization holder class模式综合实现了延迟加载和线程安全。在类加载的时候不去初始化对象。
public classSingletonClass {
privatestaticclassSingletonHolder{
private staticSingletonClass instance = newSingletonClass();
}
privateSingletonClass(){
}
publicstaticSingletonClassgetInstance(){
return SingletonHolder.instance;
}
}
据说单元素的枚举类型已经成为实现Singleton的最佳方法。
设计模式(4) -- 单例模式(Singleton)的更多相关文章
- 设计模式之单例模式——Singleton
设计模式之单例模式--Singleton 设计意图: 保证类仅有一个实例,并且可以供应用程序全局使用.为了保证这一点,就需要这个类自己创建自己的对象,并且对外有 ...
- 乐在其中设计模式(C#) - 单例模式(Singleton Pattern)
原文:乐在其中设计模式(C#) - 单例模式(Singleton Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 单例模式(Singleton Pattern) 作者:weba ...
- 【设计模式】单例模式-Singleton
[设计模式]单例模式-SingletonEnsure a class has only one instance, and provide a global point to access of it ...
- 设计模式之——单例模式(Singleton)的常见应用场景
单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...
- 设计模式之单例模式(Singleton Pattern)
单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...
- 设计模式一: 单例模式(Singleton)
简介 单例模式是属于创建型模式的一种(另外两种分别是结构型模式,行为型模式).是设计模式中最为简单的一种. 英文单词Singleton的数学含义是"有且仅有一个元素的集合". 从实 ...
- 设计模式之——单例模式(Singleton)的常见应用场景(转):
单例模式(Singleton)也叫单态模式,是设计模式中最为简单的一种模式,甚至有些模式大师都不称其为模式,称其为一种实现技巧,因为设计模式讲究对象之间的关系的抽象,而单例模式只有自己一个对象,也因此 ...
- java设计模式之 单例模式 Singleton
static 的应用 单例模式 Singleton 单例:保证一个类在系统中最多只创建一个实例. 好处:由于过多创建对象实例,会产生过多的系统垃圾,需要GC频繁回收,由于GC会占用较大的系统资源,所有 ...
- 【设计模式】单例模式 Singleton Pattern
通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance) 的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...
随机推荐
- excel 无法打开文件,提示:向程序发送命令时出现问题
以下的方法以Excel为例,请一个一个的使用,总会有一个适合你的. 1 .兼容性 鼠标右击桌面Excel(或其他)的快捷方式,选“兼容性”,把以管理员身份运行此程序前的勾去掉,就一切ok 了. 如果桌 ...
- oracle删除用户所有表
在删除数据表的时候往往遇到外键约束无法删除的情况,我们可以通过以下几步将数据库表删除,建议在删除库之前先对数据库进行备份,养成良好习惯. 1.删除外键 --查询用户所有表的外键,owner条件为use ...
- BZOJ 3672 购票
Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国\(n\)个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与 ...
- uva 1203 - Argus
简单的优先队列的应用: 代码: #include<queue> #include<cstdio> using namespace std; struct node { int ...
- QQ 群也能接收告警啦!团队沟通力 Up Up!
截止到昨天,你已经可以通过 OneAlert 的「排班」和「分派」功能,来对告警进行有序地分发,解决团队协作效率低的问题了.然而 OneAlert 觉得自己还可以更进一步,把团队沟通困难的问题也解决掉 ...
- ibatis 中isNull, isNotNull与isEmpty, isNotEmpty区别
在iBATIS中isNull用于判断参数是否为Null,isNotNull相反 isEmpty判断参数是否为Null或者空,满足其中一个条件则其true isNotEmpty相反,当参数既不为Null ...
- 居然还有WM_TIMECHANGE(只在用户手动改变系统时间时才会产生作用)
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- TCP/IP 邮件的原理
邮件通过SMTP协议来实现,有它的服务器SMTP服务器. 它是怎么在万维网中运行的呢? 我们来看看两个案例,下面的两个图来展示. 案例一: Alice通过传统的邮件服务器发送给Bob,Bob通过HTT ...
- Google Map API 学习六-设置infoWindow的长宽
- 性能指标--并发用户数(Concurrent Users)
并发用户数是指:在某一时间点,与被测目标系统同时进行交互的客户端用户的数量. 并发用户数有以下几种含义: 1. 并发虚拟用户数(Concurrent Virtual Users,Users_CVU) ...