创建型模式
- 单例模式
- 工厂模式
- 建造者模式
- 原型模式
- 对象池模式
单例模式
单例模式(Singleton pattern)是最常用的设计模式,它具有易于理解、使用简便等特点。有时候单例模式会过度使用或者在不合适的场景下使用,这样造成弊大于利的后果。
单例模式,顾名思义,用来保证一个对象只能创建一个实例,此外,它还提供了对实例的全局访问方法。
单例模式的实现很简单,只需要由单个类组成。为确保单利实例的唯一性,所有的单利构造器都需要被声明为私有的(private),再通过声明静态(static)方法实现全局访问获得该单例实例。
public class Singleton
{
private static Singleton instance;
private Singleton()
{
//TODO
}
public static Singleton getInstance()
{
if(null == instance){
instance = new Singleton();
}
return instance;
}
public vid doSomething()
{
//TODO
}
}
当我们在代码中使用该单例对象的时候,调用方式如下:
Singleton.getInstance().doSomething();
1. 同步锁单例模式
单例模式的实现很简单且高效,但是在多线程中的应用却不能这样随意,如果实例为空,那么就会有出现两个或者多个线程同时调用getInstance()的情况。这就会出现实例化多个对象的情况出现。
解决办法很简单,我们只需要创建一个代码块来检查实例是否空线程安全。
- 向getInstance方法的声明中添加synchronized关键字来保证其线程安全:
public static synchronized Singleton getInstance(){
//TODO
}
- 用synchronized代码块包装 if( instance == null ) 条件。在这一环境中使用synchronized代码块时,需要制定一个对象来提供锁,Singleton.class对象就起这种作用。
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
2. 拥有双重校验锁机制的同步锁单例模式
上一个实现方式可以保证线程安全,但同时带来了延迟。用来检查实例是否被创建的代码块是线程同步的,也就是这个代码块同一时刻只能被一个线程执行,但是同步锁(locking)只有在实例没有被创建的情况下才起作用,如果单例实例已经被创建了,那么任何线程都希望能够用非同步的方式获取当前的实例。
只有在单例模式为实例化的情况下,才能在synchronized代码块前添加附加条件移动线程安全锁:
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
这是个很聪明的校验方式,注意到instance==null条件被检查了两次,因为我们需要保证synchronized代码块中也要进行一次检查
3. 无锁的线程安全单例模式
如何不通过锁来使得单例模式线程安全呢?
Java中单例模式的最佳实践中,类只会加载一次,通过声明时直接实例化静态成员的方式来保证一个类只有一个实例。这种实现方式避免了使用同步锁和判断实力是否被创建的额外检查:
public class LockFreeSingleton{
private static final LockFreeSingleton instance = new LockFreeSingleton();
private LockFreeSingleton(){
//TODO
}
//这里的synchronized的意义在哪里呢?《设计模式与实践》书中有synchronized,但是笔者暂时没读懂这个synchronized的意义
public static synchronized LockFreeSingleton getInstance(){
return instance;
}
public void doSomething(){
//TODO
}
}
4. 提前加载和延迟加载
上述方法,在早期版本的Java中被认为是提前加载单例模式,但是在新版本的Java中,类只有在使用的时候才会被加载,所以它算是一种延迟加载模式。此外,类加载的时机主要取决于JVM的实现机制,因而版本之间会有不同。所以进行设计的时候,要避免与JVM的实现机制进行绑定。
如果确实需要提前实例化,可以在程序的开始通过调用getInstance方法强制执行。
Singleton.getInstance();
参考(学习笔记来自于):
《Java设计模式与实践》