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

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

单例模式也叫单子模式,属于创建型模式。

单例模式可分为饱汉(懒汉)式单例和饥汉(饿汉)式单例两种。

单例设计模式是一种非常常见的设计模式,如果整个系统中允许某个类只存在唯一实例,那么就可以使用单例模式。

特别是:

1.初始化这个实例需要加载比较重的资源;

2.该实例要被频繁调用;

3.系统允许只有一个唯一实例;

那么,原则上必须使用单例模式。

单例模式看上去非常简单,但是在饱汉(懒汉)式单例模式的使用中,需要留意线程不同步和不同写法的代码在编译过程产生的单例bug,饥汉(饿汉)式单例则不存在这个问题。

这里推荐一种最规范的饱汉式单例模式写法,完全摆脱多线程和代码编译产生的单例

该写法由Google工程师Bob Lee发明,属于懒汉单例模式。解决了饱汉单例模式两大难题。

public class SingletonClass{

private SingletonClass(){} ;
private static class SingletonClassInstance{
private static final SingletonClass instance = new SingletonClass() ;
}
public static SingletonClass getInstance(){
return SingletonClassInstance.instance ;
}
}

1.饿汉式单例模式:

public class SingletonClass{

private SingletonClass(){} ;
private static SingletonClass instance = new SingletonClass() ;
public static SingletonClass getInstance(){
return instance ;
}
}

看代码,这个实例是静态的,且在系统初始化的时候就已经初始化,并且永久存在。这就是饿汉式单例。因为是系统初始化的时候就存在,所以该实例不会因为线程的调度产生,所以不会存在线程安全问题。并且代码结构简约严谨,不会因为编译过程中的代码调优而改变代码的执行顺序,所以也不会产生编译bug。

下面看饱汉式单例的举例,我们通常所说的惰性加载(lazy load),程序初始化的时候单例实例并不初始化,需要等线程调用的时候才初始化这个实例。

2.饱汉式单例模式:

public class SingletonClass{

private SingletonClass(){} ;
private static SingletonClass instance = null ;
public static SingletonClass getInstance(){
if(instance == null){
instance = new SingletonClass() ;
}
return instance ;
}
}

在多线程环境中,CPU发生时间片切换,两个或多个线程有可能几乎是同一时间执行的,那么,这个实例同时被认为是null,就会多次被创建,虽然可能对性能的影响微乎其微,但是已经违反了单子模式的设计初衷。

如何既要使用懒汉式单例模式,又要保证线程安全?很多蹩脚的程序员自然想到了使用线程阻塞(synchronized关键字)。这很可笑,synchronized本来就对性能有很大影响,还有必要使用懒汉式单例吗?

下面我们给懒汉式单例加个锁:

public class SingletonClass{

private SingletonClass(){} ;

private static SingletonClass instance = null ;

public synchronized static SingletonClass getInstance(){

if(instance == null){

instance = new SingletonClass() ;

}

return instance ;

}

}

这样性能不好,换个好点的加锁方式:

public class SingletonClass{

private SingletonClass(){} ;
private static SingletonClass instance = null ;
public static SingletonClass getInstance(){
synchronized(SingletonClass.class){
if(instance == null){
instance = new SingletonClass() ;
}
}
return instance ;
}
}

看上去性能好像好多了,但是还是不够好:

public class SingletonClass{

private SingletonClass(){} ;
private static SingletonClass instance = null ;
public static SingletonClass getInstance(){
if(instance == null){
synchronized(SingletonClass.class){
if(instance == null){
instance = new SingletonClass() ;
}
}
}
return instance ;
}
}

这样看上去完美了。这就是双锁实现单子模式。

枚举

public enum Singleton2 {

INSTANCE ;
public void whatevermethod(){
}
}

 这种方式是Effective Java作者Josh Bloch 提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象,可谓是很坚强的壁垒啊,不过,个人认为由于1.5中才加入enum特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。

转载地址:http://ehdzm.baihongyu.com/

你可能感兴趣的文章
重建二叉树 (剑指offer第六题)
查看>>
爬虫基础 pyquery 详解
查看>>
QT creator+OpenCV2.4.2+MinGW 在windows下开发环境配置
查看>>
Allegro PCB Design GXL (legacy) 设置十字大光标
查看>>
数据结构--图的定义和存储结构
查看>>
[C#参考]委托机制
查看>>
linux常用命令
查看>>
自然杂志上的影评
查看>>
SQL Server 存储过程
查看>>
Appium自动化测试1 - 安装部署
查看>>
广州.NET微软技术俱乐部微信群各位技术大牛的blog
查看>>
《Redis设计与实现》之第九章:数据库
查看>>
10月10日学习内容整理:socketserver模块,ftp作业讲解
查看>>
P1352 没有上司的舞会
查看>>
Bzoj 1648: [Usaco2006 Dec]Cow Picnic 奶牛野餐 深搜,bitset
查看>>
关于《淘宝技术这十年》
查看>>
C#使用log4net记录日志
查看>>
halcon
查看>>
servlet过滤器
查看>>
maven向本地仓库导入jar包(处理官网没有的jar包)
查看>>