写点什么

三分钟看完单例模式的八个例子

用户头像
4ye
关注
发布于: 4 小时前

实现单例模式的八种模式:饿汉式,懒汉式,双重检查锁模式,静态内部类模式,序列化模式,注册式之枚举,注册式之容器,线程实现 ThreadLocal


参考大神 Tom 的《Spring 5 核心原理与 30 个类手写实战-谭勇德》


单例模式 Singleton Pattern

确保一个类在任何场景下只有一个实例,并提供一个全局访问点

使用场景

J2EE 标准中的 ServletContext Serv etContextConfig 等、 Spring 框架应用中的 ApplicationContext 、数据库的连接池 也都是单例形式

饿汉式

在类加载的时候就<font style='color:#0099ff'>立即初始化</font>,并且创建单例对象,属于<font style='color:#0099ff'>线程安全</font>


SpringIOC 容器 ApplicationContext 就是典型的饿汉式单例模式


优点: 没有加任何锁、执行效率比较高,用户体验比懒汉式单例模式更好。

缺点: 类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,有可能“占着茅坑不拉屎


package com.example.demo.singleton;


*/***
** 饿汉式*
*** *@author* *Java4ye*
** @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* *Java4ye*
** @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* *Java4ye*
** @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* *Java4ye*
** @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* *Java4ye*
** @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* *Java4ye*
** @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* *Java4ye*
** @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* *Java4ye*
** @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();
}
}




}
复制代码


  1. 懒汉式



  1. 反射破坏单例模式



有什么不对的请多多指教,阿里嘎多😄


最后

欢迎小伙伴们来一起探讨问题~


如果你觉得本篇文章还不错的话,那拜托再点点赞支持一下呀😝

让我们开始这一场意外的相遇吧!~

欢迎留言!谢谢支持!ヾ(≧▽≦*)o 冲冲冲!!

我是 4ye 咱们下期应该……很快再见!! 😆

如果文章对您有所帮助,欢迎关注公众号 J a v a 4 y e 😆


发布于: 4 小时前阅读数: 3
用户头像

4ye

关注

公众号:J a v a 4 y e 2021.07.19 加入

还未添加个人简介

评论

发布
暂无评论
三分钟看完单例模式的八个例子