标准 专业
多元 极客

设计模式实验室(21)——单例模式

什么是单例模式?

单例模式是一种创建型模式。

单例模式确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,它提供全局的访问方法,用于为系统提供单例对象。

单例模式是一种非常简单的设计模式,由于它是在JVM中有且仅有一个,所以这个单例对象的线程安全问题,是我需要着重关注的,也因此衍生出了多种单例模式的写法。

核心结构

单例模式很简单,具体有如下关注点:

  • 私有静态成员变量。
  • 全局静态方法,用于提供单例实例化对象。
  • 私有构造方法。

代码分析

单例模式有很多种实现方式,我们先写一个最简单的单例模式,懒汉单例模式(Lazy-Singleton):

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/10 0010.
 * 单例模式——懒汉模式
 */
public class LazySingleton {

    private static LazySingleton lazySingleton;

    private LazySingleton() {

    }

    public static LazySingleton getInstantce() {
        if(null == lazySingleton) {
            lazySingleton = new LazySingleton();
        }
        return lazySingleton;
    }

    public static LazySingleton getLazySingleton() {
        return lazySingleton;
    }
}

懒汉模式采用了延迟加载的策略,即什么时候需要我了,我才生产一个对象给你,当然在null == lazySingleton时,如果这个时候并发请求,就会出现线程不安全的问题,所以我们可以使用sychronized内置锁对这个方法进行上锁:

public static sychronized LazySingleton getInstantce() {
	if(null == lazySingleton) {
    	lazySingleton = new LazySingleton();
     }
     return lazySingleton;
}

这样加锁,对多线程场景是一种摧残,我们需要不时的获取、释放锁,极大的消耗了性能(试想一下,这是传统的数据库连接),有没有一种不需要上锁的线程安全的写法呢?

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/10 0010.
 * 单例模式——饿汉模式
 */
public class HungrySingleton {

    private static HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton() {

    }

	public static HungrySingleton getInstance() {
        return hungrySingleton;
    }
}

这种方式俗称饿汉单例模式,为什么说它是线程安全的呢?因为当类被加载时,静态成员变量也随着进行了加载,这个时候单例对象已经被创建,不会出现各种创建单例对象的情况。

忽然间发现,在类加载的时候就在JVM中创建单例对象是一个绝佳的思想,除了饿汉单例模式,还有什么比较装逼的写法呢?

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/11 0011.
 * 单例模式——内部实现
 */
public class InnerSingleton {

    private InnerSingleton() {

    }

	public static InnerSingleton getInstance() {
        return Singleton.innerSingleton;
    }

    private static class Singleton {

        private final static InnerSingleton innerSingleton = new InnerSingleton();
    }
}

静态内部类实现方式闪亮登场,如果你还不明白静态内部类的作用,或者是各种内部类的作用,Google大法好。

B格有了,我们回归到凡人,写一种自欺欺人的单例写法:

/**
 * Created by <sunshine> mysunshinedreams@163.com on 2017/1/11 0011.
 * 单例模式——双重校验锁
 */
public class DoubleCheckSingleton {

    private volatile static DoubleCheckSingleton doubleCheckSingleton;

    private DoubleCheckSingleton() {

    }

    public static DoubleCheckSingleton getInstance() {
        if (doubleCheckSingleton == null) {
            synchronized (doubleCheckSingleton) {
                if (doubleCheckSingleton == null) {
                    doubleCheckSingleton = new DoubleCheckSingleton();
                }
            }
        }
        return doubleCheckSingleton;
    }

    public DoubleCheckSingleton getDoubleCheckSingleton() {
        return doubleCheckSingleton;
    }
}

其实双重校验锁的写法,就是对之前对方法上锁的一种更细粒度的同步机制。

模式总结

优点

  • 提供系统性能,对于需要经常创建、销毁的对象,单例模式无异是一种解脱。
  • 严格控制外部调用何时、如何调用。

缺点

  • 没有针对接口变成,扩展难度大。
  • 违背了单一职责的原则,单例类既承担创建对象的角色,还承担了分配的对象的角色。

适用场景

  • 来来回回只需要这一个对象,比如说数据库连接(连接池对数据库的连接只是稍稍做了优化)。
  • 对象只提供一个公共访问点,其他资源外部调用无法访问。

 

赞(0) 投币

评论 抢沙发

慕勋的实验室慕勋的研究院

码字不容易,路过请投币

支付宝扫一扫

微信扫一扫