什么是单例模式
-
单例模式(Singleton Pattern)是一个比较简单的模式,实际应用很广泛,比如 Spring 中的
Bean
实例就是一个单例对象。 -
定义:确保某一个类 只有一个实例,而且自行实例化并向整个系统提供这个实例。
单例模式的优缺点
-
评价任何一种事务都要从两个方面去看,不能单一的评价。下面来看看单例模式有什么优缺点。
优点
-
只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
-
单例模式可以避免对资源的多重占用,例如一个写文件动作,由于只有一个实例存在 内存中,避免对同一个资源文件的同时写操作。
-
单例模式可以在系统设置全局的访问点,优化和共享资源访问,例如可以设计一个单 例类,负责所有数据表的映射处理。
缺点
-
单例模式一般没有接口,很难扩展(根据环境而定)。
-
单例模式与单一职责原则有冲突。一个类应该只实现一个逻辑,而不关心是否是单例的。
单例模式的实现
-
单例模式有很多的实现方式,但是各种实现的方式都有其优缺点,下面来看看各种的实现方式。
-
单例模式的实现满足以下几点:
-
构造方法私有。
-
有一个静态方法获取该类的实例。
-
该类保证只有一个实例。
-
懒汉式
-
懒汉式是当用到这个对象的时候才会创建。
-
优点:只有用到的时候才会创建这个对象,因此节省资源。
-
简单的实现如下:
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
复制代码
-
上面的代码算是基本满足了单例模式,但是不能满足线程安全,一旦在多线程的环境下仍然是不能保证该类是单例的。
-
如何保证线程安全,当然是加锁了,我们可以加线程同步锁
synchronized
,实现如下:
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
复制代码
-
此种实现方式虽然满足了线程安全,但是加锁势必会影响性能。
饿汉式
-
饿汉式和懒汉式恰巧相反,在类加载的时候就创建实例。
-
优点:还没用到就创建,浪费资源。
-
缺点:在类加载的时候就创建,线程安全。
-
实现如下:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
复制代码
双重校验锁
-
属于懒加载的一种实现方式,采用双重校验的机制,在多线程的情况仍然保持高性能。
-
实现如下:
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
复制代码
匿名内部类/静态内部类
-
利用静态变量、静态代码块、静态方法都是在类加载的时候只加载一次的原理。
-
实现如下:
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
复制代码
总结
-
单例模式的实现虽然很简单,但是也要确保实现的性能和线程安全的问题。
-
单例模式的实现主流的就是以上介绍的几种,分别是
懒汉式线程不安全
、懒汉式线程安全
、饿汉式
、双重校验锁的实现
、静态内部类的实现
。这几种方式各有优缺点,陈某推荐使用静态内部类的实现方式。 -
单例模式也是Spring使用的一种设计模式,保证了
Bean
的单实例才能管理和监控Bean的创建和销毁。