设计模式

178 阅读3分钟

一、单例设计模式


1、单例设计模式的定义

单例设计模式:一个类只允许创建一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫做单例设计模式,简称单例模式

2、单例设计模式的用处

从业务概念上,有些数据在系统中只应该保存一份,就比较适合设计为单例类。比如,系统的配置信息类。

3、如何实现一个单例设计模式

  • 构造函数需要是private访问权限的,这样才能避免外部通过new创建实例
  • 考虑对象创建时的线程安全问题
  • 考虑是否支持延迟加载
  • 考虑getInstance()性能是否高(是否加锁)

4、单例设计模式的经典实现方式

1)饿汉式

饿汉式的实现方式比较简单。在类加载的时候,instance静态实例就已经创建并初始化好了,所以instance实例的创建过程是线程安全的。不过,这样的实现方式不支持延迟加载。

/**
 * todo 饿汉式(静态常量)
 */
public class Singleton {
    private AtomicInteger id = new AtomicInteger(0);
    private static final Singleton instance = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
    public Integer getId(){
        return id.incrementAndGet();
    }
}

2)懒汉式

有饿汉式,对应的,就有懒汉式。懒汉式相对于饿汉式的优势是支持延迟加载。

/**
 * todo 懒汉式(同步方法)
 */
public class Singleton {
    private AtomicInteger id = new AtomicInteger(0);
    private static Singleton instance;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
    public Integer getId(){
        return id.incrementAndGet();
    }
}

不过懒汉式的缺点也很明显,我们给getInstance()这个方法加了一把大锁(synchronized),导致这个函数的并发度很低。量化一下的话,并发度是1,也就相当于串行操作了。而这个函数是在单例使用期间,一直会被调用。如果这个单例类偶尔会被用到,那这种实现方式还可以接受。但是,如果频繁地用到,那频繁加锁、释放锁及并发度低等问题,会导致性能瓶颈,这种方式是不可取的。

####3)双重检查 饿汉式不支持延迟加载,懒汉式有性能问题,不支持高并发。再来看一种既支持延迟加载、又支持高并发的单例实现方式,也就是双重检查实现方式。

/**
 * todo 懒汉式(双重检查)
 */
public class Singleton {
    private AtomicInteger id = new AtomicInteger(0);
    private static volatile Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if(instance == null) {
            synchronized (Singleton.class) {
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
    public Integer getId(){
        return id.incrementAndGet();
    }
}

在这种实现方式中,只要instance被创建之后,即便再调用getInstance()函数也不会再进入到加锁逻辑中了。所以,这种实现方式解决了懒汉式并发度低的问题

4)静态内部类

我们再来看一种比双重检查更加简单的实现方法,那就是利用java的静态内部类。它有点类似饿汉式,但又能做到延迟加载。

/**
 * todo 静态内部类
 */
public class Singleton {
    private AtomicInteger id = new AtomicInteger(0);
    private Singleton() {}
    private static class SingletonInstance {
        private static final Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonInstance.instance;
    }
    public Integer getId(){
        return id.incrementAndGet();
    }
}

5)枚举

最后,我们介绍一种最简单的实现方式,基于枚举类型的单例实现。这种实现方式通过Java枚举类型本身的特性,保证了实例创建的线程安全性和实例的唯一性。

/**
 * todo 枚举
 */
public enum Singleton {
    INSTANCE;
    private AtomicInteger id = new AtomicInteger(0);
    public Integer getId(){
        return id.incrementAndGet();
    }
}

二、工厂设计模式


三、建造者设计模式


四、原型设计模式