设计模式(1)-单例模式

单例模式的理解比较简单,在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在。

这样的模式有几个好处:

1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销。

2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力。

3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。

创建步骤:

1、构造方法私有化

2、对外提供公有的调用方法

实例:

// 饿汉式单例
public class HungrySingleton {

    private static HungrySingleton INSTANCE = new HungrySingleton();

    // 构造方法私有化
    private HungrySingleton() {}

    // 对外提供公有的调用方法
    public static HungrySingleton getInstance() {
        return INSTANCE;
    }
}

上面这是最简单的单例模式写法,写法简单,当然就有它的弊端,不管这个类有没有被使用,它都会先把自己实例化。

所以,就有下面第一个优化版本的实现。

// 懒汉式单例
public class LazySingleton {

    /**
     * 这里之所以用volatile修饰,是因为后面的new LazySingleton()不是原子操作
     * 它会经历三步操作
     * 1.分配内存空间
     * 2.执行构造方法,初始化对象
     * 3.将对象指向空间
     * 如果被指令重排,第一个对象先执行了132,那么随后的对象有可能会获取到一个空对象
     */
    private volatile static LazySingleton INSTANCE;

    // 构造方法私有化
    private LazySingleton() {}

    /**
     * synchronized修饰,防止多线程造成的数据混乱
     * synchronized之所以加载方法内部,是因为只有当singleton实例为空是创建实例需要防止多线程竞争,其他时候不需要
     * 而两次为空判断,第一次是只有当Singleton为空的之后需要加锁,第二个为空判断是因为前面的为空判断可能有多个线程符合条件
     * 但是第一个线程加锁,并创建了实例,那么这个时候,后面等待的线程就不应该再创建了,所以当后面的线程等到锁时还需要再做一次判断
     * @return
     */
    public static LazySingleton getInstance() {
        if (INSTANCE == null) {
            synchronized (LazySingleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new LazySingleton();
                }
            }
        }
        return INSTANCE;
    }

}

上面这个实例用synchronized实现了懒加载,但是由于加锁,所以并发下,会影响效率。

所以,就有下面第二个优化版本的实现。

// 静态内部类懒汉式单例
public class InnerClassSingleton {

    // 构造方法私有化
    private InnerClassSingleton() {}

    public static InnerClassSingleton getInstance() {
        return InnerClass.INSTANCE;
    }

    public static class InnerClass {
        public static InnerClassSingleton INSTANCE = new InnerClassSingleton();

    }
    
}

上面使用了静态内部类隐藏了类的实例化,没有加锁,所以效率上比加锁的好。

你可能感兴趣的:(设计模式)