基于容器的单例模式,与享元模式类似,我们也可以使用容器单例模式,来管理多个单例对象,那我们通过coding,debug,讲解的方式来学习一下
package com.learn.design.pattern.creational.singleton;import org.apache.commons.lang3.StringUtils;import java.util.HashMap;
import java.util.Map;/*** 容器的单例类* 那这个类实现起来非常简单* 我们来操作一下* * * * @author Leon.Sun**/
public class ContainerSingleton {/*** 我们没有写他的private构造器* 这样我们直接调用静态方法* 这种public的方法* 就OK了* 然来到Test里面* * */private ContainerSingleton(){}/*** 首先声明一个Map* 我们的KEY使用一个String* value就用Object* 这个叫singletonMap* new一个HashMap* 这个泛型也写上* 那这个map就写好了* 本身这个Map作为缓存的话* 要往里放对象* 也好取对象* 那很简单的* * */private static Map<String,Object> singletonMap = new HashMap<String,Object>();/*** putInstance两个参数* 一个是key* 另外是instance* 因为它是一个map* 可以管理很多对象* 然后做一个简单的判断* * * @param key* @param instance*/public static void putInstance(String key,Object instance){/*** 用blank来判断key* 并且instance不为null* 当这种情况下* 我们才会往里边放* 那在放之前呢* 我们还要用map来判断一下* * Thread0进到这里面他开始判断* 判断肯定正常* key传的是object* value也是一个object* 注意它是@420* * */if(StringUtils.isNotBlank(key) && instance != null){/*** singletonMap.containsKey取反* 当不包含这个key的时候* 我们才会真正的往里放* put key和instance* 那所谓的容器单例呢* 就是通过这个map呢去实现单例对象的一个容器* 那这里是保证key的合法性和唯一性* 那接下来也很简单* * 进入到这里肯定是不存在的* 因为map里面的size还是0* * */if(!singletonMap.containsKey(key)){/*** 这一行先不动* 切另一个线程* 他也会同样的进来* 那我们看一下这个instance* 是449* 另外一个instance是420* 也就是说在放的时候* 放了两个对象* 但是他们的key是同一个* 也就是说在初始化的时候* 这个对象是有可能放多个的* 那具体还要看线程的数量* 但是一旦放置完成呢* 我们在取的时候* 就只会取一个呢* 因为后执行的* 把之前执行的* 覆盖掉* 因为他们的key一样的* 那put ok了* Thread0里面放的是420* 我们直接F8过来* 刚刚有说* Thread0放的是420* 我们打开这个map* 我们可以看到map里面放的是420* 我们再切回Thread1* 执行put* 然后F8* Thread1也到getInstance这里呢* 我们看一下map里面的值* 里面已经变成449* 也就是说后执行的Thread1* 将要获取449这个Object* 那我们再切回Thread0* 看一下这个Map* 他已经变成449了* 你看上去这里将要返回同一个对象* 但是有一点* 我们现在在干预线程* 如果不干预线程的话* 例如Thread0先放置成功* 他就立刻返回了* Thread1才去放置* Thead1返回* 那这样的话他们返回的对象就不是同一个了* 我们把断点取消* 直接F8过* 从结果看上Thread0和Thread1返回的都是同一个对象* 但是他们中间还是有隐患的* 所以这种单例模式适用场景之前也说了* 根据实际的业务需要* 我们再看一下这个类* 我们想一下* HashMap他本身就不是线程安全的* 那如果我们把它改成Hashtable的话* 会不会就变成线程安全呢* 当然Hashtable是线程安全的* 我们如果使用Hashtable的话* 这种模式的单例模式就是线程安全的* 但是我们频繁去取的时候* 建议使用同步锁* 不建议使用Hashtable* 那我们可以折中一下* 但是我们使用了静态的HashMap* 而且直接操作了这个map* 那在这种场景下呢* ConCurrentHashMap并不是绝对的线程安全* 所以我们不考虑安全机制的话* 这种容器单例模式* 也是有一定适用场景的* 在安卓的SDK也用的比较多* JDK中也有这种模式* 那后边我们会讲解一些单例模式在源码中的应用* JDK中使用容器解决单例模式的一个方案* 和这个比较类似* 所以在使用这种模式的时候* 我建议它使用Hashtable* 所以呢这种单例模式* 是一个平衡* 根据业务场景来判断* 如果我们系统中单例模式非常多的话* 我们也可以考虑用一个容器把单例* 他的优点是统一管理* map相当于一个缓存* 确认是线程不安全* * * */singletonMap.put(key,instance);}}}/*** 参数是key* * * @param key* @return*/public static Object getInstance(String key){/*** 从singletonMap直接get key就可以了* 非常简单* 这种写法非常时候容器在初始化的时候* 我们就把多个单例对象放入到singletonMap里边* 统一管理* 那在使用的时候呢* 通过key直接从map当中获取单例对象* 那这里面我们也联想一下* 假设我们认为singletonMap是一个容器的话* 对于Spring容器* Spring容器里讲的单例和我们现在讲的单例* 是没有关系的* 但是可以类比一下* 我们从Spring容器里面取对象的时候* 默认如果不配置的话* 是一个单例的* 那如果我们在类上加上注解* 或者配置bean的属性为prototype属性的话* 那他就变成一个多例的* 但对于这一块我们先不深入讲解* 那我们先回来接着说这个* 那我们看一下* 这里面我们使用HashMap* 很明显的* 如果用HashMap肯定不是线程安全的* 但是如果我们使用他* 在类初始化的时候* 去把这个map初始化完成* 也就是把所有的单例对象都生成完* 放到这里边* 用的时候直接用* 这样是可以的* 所以这种单例模式* 还是要看具体的业务场景* 那我们简单测试一下* 还是用多线程debug来看一下* 这种模式单例模式实现方案安全问题* 首先我们打开Test这个类* Test类比较多* 我们看Singleton里面的* * * */return singletonMap.get(key);}
}
package com.learn.design.pattern.creational.singleton;public class T implements Runnable {@Overridepublic void run() {
//        LazySingleton lazySingleton = LazySingleton.getInstance();
//        System.out.println(Thread.currentThread().getName()+"  "+lazySingleton);
//        LazyDoubleCheckSingleton instance = LazyDoubleCheckSingleton.getInstance();
//        StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();;ContainerSingleton.putInstance("object",new Object());/*** 从这里面取一下instance* 以为这里调用的是静态方法* 所以呢* 回到这个类里面* * */Object instance = ContainerSingleton.getInstance("object");
//        ThreadLocalInstance instance = ThreadLocalInstance.getInstance();System.out.println(Thread.currentThread().getName()+"  "+instance);}
}
package com.learn.design.pattern.creational.singleton;import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//        LazySingleton lazySingleton = LazySingleton.getInstance();//        System.out.println("main thread"+ThreadLocalInstance.getInstance());
//        System.out.println("main thread"+ThreadLocalInstance.getInstance());
//        System.out.println("main thread"+ThreadLocalInstance.getInstance());
//        System.out.println("main thread"+ThreadLocalInstance.getInstance());
//        System.out.println("main thread"+ThreadLocalInstance.getInstance());
//        System.out.println("main thread"+ThreadLocalInstance.getInstance());/*** 现在是两个线程* 我们把往容器放对象的这个过程* 放到线程里边* 让他们并发去放* 来到T里边* * */Thread t1 = new Thread(new T());Thread t2 = new Thread(new T());t1.start();t2.start();System.out.println("program end");//        HungrySingleton instance = HungrySingleton.getInstance();
//        EnumInstance instance = EnumInstance.getInstance();
//        instance.setData(new Object());//        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
//        oos.writeObject(instance);//        File file = new File("singleton_file");
//        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));//        HungrySingleton newInstance = (HungrySingleton) ois.readObject();
//        EnumInstance newInstance = (EnumInstance) ois.readObject();//        System.out.println(instance.getData());
//        System.out.println(newInstance.getData());
//        System.out.println(instance.getData() == newInstance.getData());//        Class objectClass = HungrySingleton.class;
//        Class objectClass = StaticInnerClassSingleton.class;//        Class objectClass = LazySingleton.class;
//        Class objectClass = EnumInstance.class;//        Constructor constructor = objectClass.getDeclaredConstructor();
//        Constructor constructor = objectClass.getDeclaredConstructor(String.class,int.class);
//
//        constructor.setAccessible(true);
//        EnumInstance instance = (EnumInstance) constructor.newInstance();
//        EnumInstance instance = (EnumInstance) constructor.newInstance("Geely",666);//
//        LazySingleton newInstance = (LazySingleton) constructor.newInstance();
//        LazySingleton instance = LazySingleton.getInstance();//        StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
//        StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton) constructor.newInstance();//        HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();
//        HungrySingleton instance = HungrySingleton.getInstance();//        System.out.println(instance);
//        System.out.println(newInstance);//        System.out.println(instance == newInstance);//        EnumInstance instance = EnumInstance.getInstance();
//        instance.printTest();}
}

单例设计模式-容器单例相关推荐

  1. 单例设计模式介绍||单例设计模式八种方式——1) 饿汉式(静态常量) 2) 饿汉式(静态代码块) 3) 懒汉式(线程不安全) 4) 懒汉式(线程安全,同步方法)

    单例模式 单例设计模式介绍 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法). 比如Hibernate的 ...

  2. java软件设计模式只单例设计模式

    概述 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计 ...

  3. java饿汉式有啥作用,Java面试 - 什么是单例设计模式,为什么要使用单例设计模式,如何实现单例设计模式(饿汉式和懒汉式)?...

    什么是单例设计模式? 单例设计模式就是一种控制实例化对象个数的设计模式. 为什么要使用单例设计模式? 使用单例设计模式可以节省内存空间,提高性能.因为很多情况下,有些类是不需要重复产生对象的.如果重复 ...

  4. 设计延迟加载的“单例设计模式”

    今天看毕老师的线程部分,学到了如何设计延迟加载的单例设计模式: 单例设计模式分两种: 1.饿汉模式 2.懒汉模式 先上饿汉式代码: // 饿汉式 class Single{ private stati ...

  5. Python(25)-单例设计模式

    单例设计模式 1.单例设计模式 2.__new__方法 3.初始动作只执行一次 本系列博文来自学习<Python基础视频教程>笔记整理,视屏教程连接地址:http://yun.itheim ...

  6. 单例设计模式(拉勾教育大数据学习笔记)

    单例设计模式的概念: 在某些特殊场合中,一个类对外提供且只提供一个对象时,这样的类叫做单例类,而设计单例的流程和思想叫做单例设计模式. 单例设计模式的实现流程: 1. 私有化构造方法,使用privat ...

  7. Java设计模式——单例设计模式/权限修饰符的使用

    1. 单例模式含义 所谓的单例设计模式,就是采取一定的方法保证整个软件系统中,某个类只能存在一个对象实例. 单例设计模式 2. 单例设计模式的两种实现方法 饿汉式:不管是否需要该实例,我事先就把该实例 ...

  8. 什么是Singleton,单例设计模式

    Singleton  [ˈsɪŋɡltən] 单例模式 在java中是指单例设计模式. 单例设计模式: 单例模式可以保证系统中,应用该模式的类一个类只有一个实例.即一个类只有一个对象实例. 例如:例如 ...

  9. Java中的单例设计模式

    什么是单例设计模式 所谓单例设计模式,就是采取一定的方法保证整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法. 目的:使用着在main方法中就不可以自己创建实例对象 ...

最新文章

  1. Java程序员到什么级别可以去BAT上班?
  2. ARM:钒和铁替代固氮酶的前世今生
  3. 如何修复GIT错误:目标文件为空?
  4. 【django】HttpRequest对象
  5. windows下使用svn命令行
  6. linux 创建用户和修改新增用户默认的家目录
  7. 转:Deep learning系列(十五)有监督和无监督训练
  8. 马斯克惹麻烦?特斯拉股票一夜暴跌12%,千亿市值蒸发
  9. oracle匿名代码块执行insert,MyBatis+Oracle在执行insert时空值报错之从源码寻找解决办法...
  10. 一个类的类类型是Class类的实例,即类的字节码
  11. OpenGl 游戏编程笔记 第七章:纹理映射 (texture mapping) (一)
  12. mac下面Eclipse安装反编译插件
  13. 【十次方】十次方项目介绍
  14. S-MJLs和网络动态系统的分析与综合
  15. 如何隐藏电脑下方工具栏个别图标_小编教你电脑如何隐藏任务栏图标
  16. python xlwt 表格样式
  17. latex下的实数集R的写法
  18. 初学者应该选择什么样吉他桶型?新手入门畅销民谣吉他牌子推荐
  19. 美国名校的与机器视觉相关的研发中心网址
  20. Cadence Allegro打阵列过孔方法图文教程及视频演示

热门文章

  1. Dart 基礎 - 4
  2. 局部内部类访问它所在方法中的局部变量必须是final
  3. java中VO、PO、DTO 、DO、POJO、BO、TO
  4. php 调用java webservice
  5. 专家系列教程:遭受***后的证据有哪些?
  6. CSS各种选择符的优先级
  7. 用c语言实现随机无向图的生成,C ++程序为给定数量的边生成随机无向图
  8. 北京工业计算机考研科目,2020北京工业大学计算机考研初试科目、参考书目、招生人数汇总...
  9. RabbitMQ快速入门--介绍和安装
  10. Nginx的error_page指令