单例模式八个例子
实现单例模式的八种模式:饿汉式,懒汉式,双重检查锁模式,静态内部类模式,序列化模式,注册式之枚举,注册式之容器,线程实现ThreadLocal
单例模式八个例子使用场景饿汉式懒汉式双重检查锁模式静态内部类模式序列化模式注册式单例模式枚举式容器式线程单例实现 Thread Local测试
参考大神Tom的《Spring 5核心原理与30个类手写实战-谭勇德》
单例模式 Singleton Pattern
确保一个类在任何场景下只有一个实例,并提供一个全局访问点
使用场景
J2EE 标准中的 ServletContext Serv etContextConfig 等、 Spring 框架应用中的ApplicationContext 、数据库的连接池 也都是单例形式
饿汉式
在类加载的时候就立即初始化,并且创建单例对象,属于线程安全
SpringIOC容器ApplicationContext就是典型的饿汉式单例模式
优点:没有加任何锁、执行效率比较高,用户体验比懒汉式单例模式更好。
缺点:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能“占着茅坑不拉屎
package com.example.demo.singleton;*/*** ** 饿汉式* *** *@author* *RYZEYANG* ** @date 2020/9/6 8:19* **/*public class HungrySingleton { private static final HungrySingleton hungry=new HungrySingleton(); private HungrySingleton() { } public static HungrySingleton getInstance(){ return hungry; }}
懒汉式
使用时才去创建该对象
package com.example.demo.singleton;*/*** ** 懒汉式* *** *@author* *RYZEYANG* ** @date 2020/9/6 8:19* **/*public class LazySingleton { private static LazySingleton instance=null; private LazySingleton(){} public static LazySingleton getInstance(){ if(instance==null){ instance=new LazySingleton(); } return instance; }}
双重检查锁模式
懒汉式是线程不安全的,需要加锁。
package com.example.demo.singleton;*/*** ** 双重检查锁* *** *@author* *RYZEYANG* ** @date 2020/9/6 8:19* **/*public class LazyDoubleCheckSingleton { private static LazyDoubleCheckSingleton lazyDoubleCheckMode=null; private LazyDoubleCheckSingleton(){} public static LazyDoubleCheckSingleton getInstance(){ if (lazyDoubleCheckMode==null){ synchronized(LazyDoubleCheckSingleton.class){ if (lazyDoubleCheckMode==null){ lazyDoubleCheckMode= new LazyDoubleCheckSingleton(); } } } return lazyDoubleCheckMode; }}
静态内部类模式
package com.example.demo.singleton;*/*** ** 静态内部类模式* ** 这种形式兼顾饿汉式单例模式的内存浪费问题和 synchronized 的性能问题* ** 加载静态变量,方法,不包括这个静态内部类* ** 被外部类调用的时候内部类才会加载* *** *** *@author* *RYZEYANG* ** @date 2020/9/6 9:12* **/*public class LazyInnerClassSingleton { public static LazyInnerClassSingleton getInstance() { return InnerLazyHolder.LAZY; } private static class InnerLazyHolder { private static final LazyInnerClassSingleton LAZY = new LazyInnerClassSingleton(); } */*** ** 防止反射创建* **/* private LazyInnerClassSingleton() { if (InnerLazyHolder.LAZY != null) { throw new RuntimeException("不允许创建多个实例"); } }}
序列化模式
package com.example.demo.singleton;import java.io.Serializable;*/*** ** 序列化模式* *** *** *@author* *RYZEYANG* ** @date 2020/9/6 21:59* **/*public class SerializableSingleton implements Serializable { private static final long serialVersionUID = 7018585554862336578L; private SerializableSingleton() { } private static final SerializableSingleton INSTANCE = new SerializableSingleton(); public static SerializableSingleton getInstance() { return INSTANCE; } */*** *objectInputStream中通过这个hasReadResolveMethod去判断有没有该方法,有的话反序列化会去调用该方法* *返回类型必须是Object* **/* private Object readResolve() { return INSTANCE; }}
注册式单例模式
注册式单例模式又称为登记式单例模式 就是将每一个实例都登记到某一个地方,使用唯一的标识 。注册式单例模式有两种:一种为枚举式单例,另一为容器式单例模式
枚举式
package com.example.demo.singleton;*/*** ** 注册式单例模式又称为登记式单例模式 就是将每一个实例都登记到某一个地方,使用唯一的标识 。注册式单例模式有两种:一种为枚举式单例,另一为容器式单例模式* ** 注册式单例模式之枚举式* *** *@author* *RYZEYANG* ** @date 2020/9/6 23:18* **/*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.example.demo.singleton;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;*/*** ** 注册式单例模式又称为登记式单例模式 就是将每一个实例都登记到某一个地方,使用唯一* ** 的标识 。注册式单例模式有两种:一种为枚举式单例,另一为容器式单例模式* ** 注册式单例模式之容器式* *** *@author* *RYZEYANG* ** @date 2020/9/9 7:16* **/*public class ContainerSingleton { private ContainerSingleton(){} private static final Map<String,Object> ioc=new ConcurrentHashMap<>(); public static Object getBean(String className){ synchronized (ioc){ if (!ioc.containsKey(className)){ Object obj=null; try { obj = Class.forName(className).newInstance(); ioc.put(className,obj); } catch (InstantiationException | ClassNotFoundException | IllegalAccessException e) { e.printStackTrace(); } return obj; }else{ return ioc.get(className); } } }}
线程单例实现 Thread Local
package com.example.demo.singleton;*/*** ** 线程单例实现 Thread Local* ** 确保每一个线程只有一个实例对象* *** *@author* *RYZEYANG* ** @date 2020/9/9 7:31* **/*public class ThreadLocalSingleton { private ThreadLocalSingleton() { } private static final ThreadLocal<ThreadLocalSingleton> threadLocal = ThreadLocal.withInitial(ThreadLocalSingleton::new); public static ThreadLocalSingleton getInstance(){ return threadLocal.get(); }}
测试
先简单测试下这个 【懒汉式线程不安全版本】 和 【反射破坏单例】 这两种模式。。。其他几个写在下篇博客啦?
package com.example.demo;import com.example.demo.singleton.LazyInnerClassSingleton;import com.example.demo.singleton.LazySingleton;import org.junit.jupiter.api.Test;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.util.concurrent.LinkedBlockingDeque;import java.util.concurrent.ThreadFactory;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger;class SingletonTest { */*** ** 线程调度工厂创建线程* **/* static class ExcutorThread implements ThreadFactory { private String name; private AtomicInteger atomicInteger = new AtomicInteger(1); public ExcutorThread(String name) { this.name = name; } @Override public Thread newThread(Runnable task) { int index = atomicInteger.getAndIncrement(); Thread thread = new Thread(task); String threadName = String.format(name + ":%s", index); thread.setName(threadName); System.out.println(threadName); return thread; } } */*** ** 创建线程池* **/* public static ThreadPoolExecutor getThreadPoolExecutor(String threadFactoryName) { return new ThreadPoolExecutor(10, 20, 1, TimeUnit.MINUTES, new LinkedBlockingDeque<>(10), new ExcutorThread(threadFactoryName)); } */*** ** 懒汉式 线程不安全 测试* **/* @Test void testLazySingleton() { ThreadPoolExecutor lazyPool = getThreadPoolExecutor("LazySingleton"); for (int i = 1; i <= 30; i++) { int finalI = i; lazyPool.execute(() -> System.out.println(String.format(LazySingleton.getInstance() + "[%s]", finalI)) ); }*// lazyMode.shutdown();* } */*** ** 反射破坏单例模式* **/* @Test void testLazyInnerClassSingleton() { Class<LazyInnerClassSingleton> lazyInnerClassModeClass = LazyInnerClassSingleton.class; try { Constructor<LazyInnerClassSingleton> constructor = lazyInnerClassModeClass.getDeclaredConstructor(null); constructor.setAccessible(true); LazyInnerClassSingleton lazyInnerClassInstance = constructor.newInstance(); System.out.println(lazyInnerClassInstance); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { e.printStackTrace(); } }}
懒汉式
反射破坏单例模式
有什么不对的请多多指教,阿里嘎多?