目录
传统的创建类代码
单例类创建
(1)饿汉模式(以空间换时间,可能存在资源消耗问题)
(2)懒汉模式(可能存在线程不安全问题)
(3)方法上添加synchronized锁的懒汉模式(造成系统瓶颈)
(3)添加双重校验锁的懒汉模式(JVM指令重排可能导致程序出错)
(4)添加双重检验锁与volatile关键字的懒汉模式
(5)静态内部类的单例模式(推荐的写法)
Spring单例模式源码
单例模式(Singleton Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。
/**
* @author:py
* @date:
* @description:传统创建类实例
* @version:
*/
public class Case_1 {
public static void main(String[] args) {
Singleton singleton1 = new Singleton();
Singleton singleton2 = new Singleton();
}
}
/**
* @author:py
* @date:
* @description:单例类
* @version:
*/
class Singleton {
}
每次new Singleton()就会创建一个Singleton实例,并不符合单例类只有一个实例的要求。
Step 1. 构造函数私有化。
Step 2. 自行对外提供实例。
Step 3. 提供外界可以获得该实例的方法。
/**
* @author:py
* @date:
* @description:单例模式实例
* @version:
*/
public class Case_1 {
public static void main(String[] args) {
// Singleton singleton1 = new Singleton();
//单例
Singleton singleton2 = Singleton.getInstance();
}
}
/**
* @author:py
* @date:
* @description:单例类(饿汉模式)
* @version:
*/
class Singleton {
// step 2.自行对外提供实例
private static Singleton singleton = new Singleton();
//step 1.构造函数私有化
private Singleton(){}
//step 3.提供外界可以获得该实例的方法
public static Singleton getInstance() {
return singleton;
}
}
如果创建单例对象会消耗大量资源,可以用懒汉模式延迟创建对象。但是在多线程并发的情况下使用懒汉模式,会并发调用getInstance()方法,导致系统同时创建多个单例类实例。
/**
* @author:py
* @date:
* @description:单例模式实例
* @version:
*/
public class Case_1 {
public static void main(String[] args) {
// Singleton singleton1 = new Singleton();
//单例
Singleton singleton2 = Singleton.getInstance();
}
}
/**
* @author:py
* @date:
* @description:单例类(懒汉模式)
* @version:
*/
class Singleton {
// step 2.自行对外提供实例
private static Singleton singleton = null;
//step 1.构造函数私有化
private Singleton(){}
//step 3.提供外界可以获得该实例的方法
public static Singleton getInstance() {
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
添加synchronized锁可以保证线程安全,但在每次访问getInstance()方法时都会进行加锁和解锁的操作,同时synchronized锁添加在方法上,作用范围过大,而单例类是全局唯一的,锁的操作会成为系统的瓶颈。
/**
* @author:py
* @date:
* @description:单例模式实例
* @version:
*/
public class Case_1 {
public static void main(String[] args) {
// Singleton singleton1 = new Singleton();
//单例
Singleton singleton2 = Singleton.getInstance();
}
}
/**
* @author:py
* @date:
* @description:单例类(懒汉模式+synchronized锁)
* @version:
*/
class Singleton {
// step 2.自行对外提供实例
private static Singleton singleton = null;
//step 1.构造函数私有化
private Singleton(){}
//step 3.提供外界可以获得该实例的方法
public static synchronized Singleton getInstance() {
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
/**
* @author:py
* @date:
* @description:单例模式实例
* @version:
*/
public class Case_1 {
public static void main(String[] args) {
// Singleton singleton1 = new Singleton();
//单例
Singleton singleton2 = Singleton.getInstance();
}
}
/**
* @author:py
* @date:
* @description:单例类(懒汉模式+双重校验锁)
* @version:
*/
class Singleton {
// step 2.自行对外提供实例
private static Singleton singleton = null;
//step 1.构造函数私有化
private Singleton(){}
//step 3.提供外界可以获得该实例的方法
public static Singleton getInstance() {
//第一次校验
if(singleton == null){
synchronized (Singleton.class){
//第二次校验
if(singleton == null){
//创建对象,非原子操作
singleton = new Singleton();
}
}
}
return singleton;
}
}
上述代码中,singleton = new Singleton()指令实际可抽象为以下几条JVM指令:
//Step 1. 分配对象的内存空间
memory = allocate();
//Step 2. 初始化对象
ctorInstance(memory);
//Step 3. 设置instance指向刚分配的内存地址
singleton = memory;
其中,操作2依赖操作1,但操作3不依赖操作2,所以JVM会针对他们进行指令优化重排序。
指令重排:是指JVM为了优化指令,提高程序运行效率,在不影响单线程程序执行结果的前提下,尽可能地提高并行度。
JVM指令重排序后如下所示:
//Step 1. 分配对象的内存空间
memory = allocate();
//Step 3. 设置instance指向刚分配的内存地址,此时对象还未初始化
singleton = memory;
//Step 2. 初始化对象
ctorInstance(memory);
如果线程A正在执行这段赋值语句,在初始化分配对象之前就将其赋值给singleton引用,恰好此时线程B进入该方法判断singleton引用不为null,然后将其返回使用,就会导致程序出错。
使用volatile关键字修饰singleton字段可以禁止指令的重排序优化,阻止JVM对其相关代码进行指令重排,从而保证按既定的顺序指令执行。
/**
* @author:py
* @date:
* @description:单例模式实例
* @version:
*/
public class Case_1 {
public static void main(String[] args) {
// Singleton singleton1 = new Singleton();
//单例
Singleton singleton2 = Singleton.getInstance();
}
}
/**
* @author:py
* @date:
* @description:单例类(懒汉模式+双重校验锁+volatile关键字)
* @version:
*/
class Singleton {
// step 2.自行对外提供实例
private static volatile Singleton singleton = null;
//step 1.构造函数私有化
private Singleton(){}
//step 3.提供外界可以获得该实例的方法
public static Singleton getInstance() {
if(singleton == null){
synchronized (Singleton.class){
if(singleton == null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
/**
* @author:py
* @date:
* @description:单例模式实例
* @version:
*/
public class Case_1 {
public static void main(String[] args) {
// Singleton singleton1 = new Singleton();
//单例
__Singleton singleton2 = __Singleton.getInstance();
}
}
/**
* @author:py
* @date:
* @description:单例类(静态内部类)
* @version:
*/
class __Singleton {
//step 2.私有的静态内部类,类加载器负责加锁
private static class SingletonHolder{
private static __Singleton singleton = new __Singleton();
}
//step 1.构造函数私有化
private __Singleton(){}
//step 3.提供外界可以获得该实例的方法
public static __Singleton getInstance() {
return SingletonHolder.singleton;
}
}
Spring的依赖注入(包括lazy-init方式)都是发生在AbstractBeanFactory的getBean()方法里。getBean()方法内部调用doGetBean()方法,doGetBean()方法内部调用父类FactoryBeanRegistrySupport的父类DefaultSingletonBeanRegistry的getSingleton()方法进行Bean的创建。非lazy-init方式,在容器初始化时进行调用,lazy-init方式,在用户向容器第一次索要bean时进行调用。
getBean()、doGetBean()和getSingleton()方法的源码具体如下:
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
protected T doGetBean(String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object bean;
//省略部分代码
}
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
Map var4 = this.singletonObjects;
synchronized(this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
从getSingleton()方法中可以看到,Spring进行依赖注入时,使用了双重校验锁的单例模式。
先从缓存singletonObjects(实际是一个ConcurrentHashMap)中获取bean实例。
Spring源码DefaultSingletonBeanRegistry类中对singletonObjects进行了如下定义:
private final Map
singletonObjects = new ConcurrentHashMap(256);
如果bean实例为null,对缓存singletonObjects加锁,然后再从缓存earlySingletonObjects(实际是个HashMap)中获取bean实例,如果继续为null,就创建一个bean。
Spring源码DefaultSingletonBeanRegistry类中对earlySingletonObjects进行了如下定义:
private final Map
earlySingletonObjects = new HashMap(16);
与前面所述的单例模式使用私有构造方法创建bean不同点在于,这里是通过singletonFactory.getObject()来返回具体的beanName对应的ObjectFactory来创建bean。实际上是调用了AbstractAutowireCapableBeanFactory的doCreateBean()方法,返回了BeanWrapper包装并创建的bean实例。
doCreateBean()方法部分代码如下:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
Object var7 = mbd.postProcessingLock;
synchronized(mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable var17) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", var17);
}
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
//省略部分代码
}