单例模式

简介:

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

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

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

特别是:

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

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

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

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

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

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

该写法由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特性,用这种方式写不免让人感觉生疏,在实际工作中,我也很少看见有人这么写过。

目录
相关文章
|
7月前
|
设计模式 安全 测试技术
【C++】—— 单例模式详解
【C++】—— 单例模式详解
|
7月前
|
设计模式 安全
详细讲解什么是单例模式
详细讲解什么是单例模式
|
4月前
|
存储 设计模式 测试技术
单例模式
单例模式
|
设计模式 安全 编译器
2023-6-12-第三式单例模式
2023-6-12-第三式单例模式
73 0
|
7月前
|
设计模式 安全
【单例模式】—— 每天一点小知识
【单例模式】—— 每天一点小知识
|
设计模式 安全 Java
单例模式的运用
单例模式的运用
45 0
|
安全 Java
原来要这么实现单例模式
原来要这么实现单例模式
57 0
|
SQL 安全 Java
五种单例模式介绍
五种单例模式介绍
92 0
|
SQL 设计模式 安全
单例模式详解
单例模式详解
241 0
单例模式详解
|
设计模式 Java
单例模式的应用(2)
单例模式的应用(2)
128 0