创建性模式有五种:
1.工厂模式
①简单工厂模式(经常被用到,不属于GoF23种设计模式)
②工厂方法模式
③抽象工厂模式
2.建造者模式
3.原型模式
4.单例模式
单例设计模式
单例设计模式(Singleton Design Pattern)理解起来非常简单。一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。
优缺点
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
2、避免对资源的多重占用(比如写文件操作)。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
代码实现方式:
1.饿汉式
饿汉式的实现方式比较简单。就是在类加载的时候,instance 静态实例就已经创建并初始化好了,所以,instance 实例的创建过程是线程安全的。实现方式是不支持延迟加载,就是不管有没有使用它都已经创建好了,这也是有人觉得这种方式不太好的原因,如果实例占用资源多,比如占用内存多或初始化耗时长),提前初始化实例是一种浪费资源的行为。最好的方法应该在用到的时候再去初始化。反过来想如果初始化耗时长,那最好不要等到真正要用它的时候,才去执行这个耗时长的初始化过程,这会影响到系统的性能,比如导致响应时间过长。采用饿汉式实现方式,将耗时的初始化操作,提前到程序启动的时候完成,这样就能避免在程序运行的时候,再去初始化导致的性能问题。
public class IdGenerator {
private AtomicLong id = new AtomicLong(0);
private static final IdGenerator instance = new IdGenerator();
private IdGenerator() {}
public static IdGenerator getInstance() {
return instance;
}
public long getId() {
return id.incrementAndGet();
}
}
2.懒汉式
懒汉式相对于饿汉式的优势是支持延迟加载,缺点很明显,因为加了synchronized导致其是串行执行,并发度很低
public class IdGenerator {
private AtomicLong id = new AtomicLong(0);
private static IdGenerator instance;
private IdGenerator() {}
public static synchronized IdGenerator getInstance() {
if (instance == null) {
instance = new IdGenerator();
}
return instance;
}
public long getId() {
return id.incrementAndGet();
}
}
在spring源码(如 ReactiveAdapterRegistry)和jdk源码(如 AbstractQueuedSynchronizer)中,有如下实现, 使用一个临时局部变量来接收,这样在判断instance!=null时,传统双检锁会访问2次主存;现在利用局部变量只需要访问1次主存,性能更好。
public class Singleton {
private static volatile Singleton instance=null;
private Singleton() {
}
public static Singleton getInstance() {
Singleton temp=instance;
if (null == temp) {
synchronized (Singleton.class) {
temp=instance;
if (null == temp) {
temp=new Singleton();
instance=temp;
}
}
}
return instance;
}
}
3.双重校验
饿汉式不支持延迟加载,懒汉式有性能问题,不支持高并发。那我们再来看一种既支持延迟加载、又支持高并发的单例实现方式,也就是双重检测实现方式。在这种实现方式中,只要 instance 被创建之后,即便再调用 getInstance() 函数也不会再进入到加锁逻辑中了。所以,这种实现方式解决了懒汉式并发度低的问题。
public class IdGenerator {
private AtomicLong id = new AtomicLong(0);
private static IdGenerator instance;
private IdGenerator() {}
public static IdGenerator getInstance() {
if (instance == null) {
synchronized(IdGenerator.class) { // 此处为类级别的锁
if (instance == null) {
instance = new IdGenerator();
}
}
}
return instance;
}
public long getId() {
return id.incrementAndGet();
}
}
4. 静态内部类
利用 Java 的静态内部类。它有点类似饿汉式,但又能做到了延迟加载
public class IdGenerator {
private AtomicLong id = new AtomicLong(0);
private IdGenerator() {}
private static class SingletonHolder{
private static final IdGenerator instance = new IdGenerator();
}
public static IdGenerator getInstance() {
return SingletonHolder.instance;
}
public long getId() {
return id.incrementAndGet();
}
}
SingletonHolder 是一个静态内部类,当外部类 IdGenerator 被加载的时候,并不会创建 SingletonHolder 实例对象。只有当调用 getInstance() 方法时,SingletonHolder 才会被加载,这个时候才会创建 instance。instance 的唯一性、创建过程的线程安全性,都由 JVM 来保证。所以,这种实现方法既保证了线程安全,又能做到延迟加载。
5. 枚举最后
这种实现方式通过 Java 枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。具体的代码如下所示:
public enum IdGenerator {
INSTANCE;
private AtomicLong id = new AtomicLong(0);
public long getId() {
return id.incrementAndGet();
}
}