对于单例模式咱们其实已经很是熟悉了,若是不熟悉的话,那你随便百度一下就能看的一大堆关于单例模式的介绍。单例模式的实现是当前设计模式中能够说实现最简单的一种模式了,也很容易理解,可是其实单例模式并不是你想的那么简单哦。
下面就从几个实际的源码中来看看,单例模式在什么样的状况下会被使用。java
问你下面几个问题,若是你对这几个问题烂熟于心,那么证实你真的了解单例模式。spring
一、有几种常见的实现单例模式的方法?
二、经过序列化和反序列化能够破坏某些单例模式
三、经过反射能够破坏某些单例模式
四、能够用枚举实现单例模式,而且很是安全
五、如何针对每个线程单首创建一个单例设计模式
单例模式的实现有不少方式,这里只是我的作一个记录,供参考。缓存
package com.linkinstars.singleton; /** * (双重检查)单例模式 * @author LinkinStar */ public class DoubleCheckSingleton { private DoubleCheckSingleton(){} public volatile static DoubleCheckSingleton doubleCheckSingleton = null; public static DoubleCheckSingleton getInstance(){ if (doubleCheckSingleton == null) { synchronized(DoubleCheckSingleton.class){ if (doubleCheckSingleton == null) { doubleCheckSingleton = new DoubleCheckSingleton(); } } } return doubleCheckSingleton; } }
package com.linkinstars.singleton; /** * 饿汉式单例 * @author LinkinStar */ public class HungrySingleton { private final static HungrySingleton INSTANCE = new HungrySingleton(); public static HungrySingleton getInstance() { return INSTANCE; } private HungrySingleton() { if (INSTANCE != null) { throw new RuntimeException("Can't create singleton by reflect."); } } }
package com.linkinstars.singleton; /** * 静态内部类实现单例模式 * @author LinkinStar */ public class StaticInnerClassSingleton { private static class InnerClass { private static StaticInnerClassSingleton staticInner = new StaticInnerClassSingleton(); } public StaticInnerClassSingleton getInstance(){ return InnerClass.staticInner; } private StaticInnerClassSingleton(){} }
package com.linkinstars.singleton; /** * 枚举实现单例模式 * @author LinkinStar */ public enum EnumSingleton { /** 单例 **/ INSTANCE; private Object data; public Object getData() { return data; } public void setData(Object data) { this.data = data; } public static EnumSingleton getInstance() { return INSTANCE; } }
package com.linkinstars.singleton; /** * 单线程级别的单例 * @author LinkinStar */ public class ThreadLocalSingleton { public static final ThreadLocal<ThreadLocalSingleton> THREAD_LOCAL_SINGLETON_THREAD_LOCAL = ThreadLocal.withInitial(ThreadLocalSingleton::new); private ThreadLocalSingleton(){ } public static ThreadLocalSingleton getInstance(){ return THREAD_LOCAL_SINGLETON_THREAD_LOCAL.get(); } }
jdk中有一个Runtime的类,这个类用于获取java程序运行时的一些环境,如内存等信息。这些获取信息的方法不少都是会调用底层原生的native方法。
如:Runtime.getRuntime().maxMemory();
而后咱们进入Runtime能够看见源码中:
安全
这个是标准的饿汉式的单例
由于java程序运行时,若是要获取运行时的环境信息,总须要一个载体,而且在任何地方获取的都应该是同样的,因此用一个单例来维护这个信息,而且提供些方法,再好不过了。多线程
Spring单例模式的bean只会建立一次,若是再获取该bean,是直接从单例缓存中获取,该过程就在getSingleton(String beanName)中。
优化
这里的方法须要你细细品读,我要说明的是,单例模式确定有本身的好处,否则spring为何bean默认是单例的呢?很简单的一点是由于单例的速度快,而且对象少,占用的内存就少,若是是多例的,每次使用须要进行建立会耗时间,而且消耗内存。
可是同时单例模式也有相应的问题,就是多线程访问的时候会有线程安全的问题,多个线程操做私有变量的时候就会出现。因此在使用的单例模式的时候也要同时考虑到线程安全的问题。this
ErrorContext是MyBatis中的一个颇有意思的类,从名字咱们也能够猜到,它是用于记录当前线程的发生错的信息,获取到当前错误发生的上下文信息。
spa

咱们能够想到,当咱们每一个线程出现错误的时候不可能去影响别的线程的错误信息的记录,每一个线程确定记录属于本身的错误信息,因此ErrorContext一开始被建立,当获取的时候,针对于每一个线程自己都是获取到的对象应该是同样的。线程
单例模式使用的不少,理解它的目的和优势知道它的使用场景,能够对你的系统设计上面有更多优化的可能性。