刚刚线程1看不到线程0的重排序,我们创建一个类,这个方案是使用静态内部类来解决,一会我们也会分析一下原理,我们创建一个静态内部类,静态内部类的代理模式,JVM在类的初始化阶段,也就是class被加载后,并且被线程使用之前,都是类的初始化阶段,在这个阶段会执行类的初始化,那在执行类的初始化期间呢,JVM会去获取一个锁,这个锁可以同步多个线程,对一个类的初始化,也就是绿色的部分,基于这个特性,我们可以实现基于内部类的并且是线程安全的,延迟初始化方案,那我们看一下这个图,还是线程0和线程1,蓝色和红色,那在这种实现模式中呢,对于右侧的2和3,也就是橙色的框,这两个步骤的重排序,对于我们前面讲的,线程1并不会看到,也就是说,非构造线程是不允许看到重排序的,因为我们之前是讲的线程0来构造这个单例对象,初始化一个类,包括执行类的静态初始化,还有初始化在这个类中声明的静态变量,根据JAVA语言规范,主要分5种情况,首次发生的时候呢,一个类将被立刻初始化,这里所说的类呢,泛指包括接口interface,也是一个类,那假设这个类是A,那现在我们说一下,这几种情况,都会导致这个A类,被立刻初始化,首先呢第一种情况,有一个A类型的实例被创建,A类型中的一个静态方法被调用,第三种情况呢,是A类中声明的一个静态成员,被赋值,第四种情况,A类中声明的一个静态成员被使用,并且这个成员不是一个常量成员,前四种我们实际工作中用的比较多,第五种用的比较少,也就是说如果A类是一个顶级类,关于顶级类在JAVA语言规范里面的介绍,并且呢在这个类中,有嵌套的断言语句,这种情况呢A类也会立刻被初始化,也就是说刚刚说的五种情况,前四种是我们经常会被碰到的,只要首次发生以上说的一个情况,这个类就会被立刻初始化,把我们看一下这个图,当线程0和线程1试图想获取这个锁的时候,也就是获得class对象的初始化锁,这个时候肯定只有一个线程能获得这个锁,假设线程0获得这个锁了,线程0执行内部类的一个初始化,对于静态内部类即使23之间存在重排序,但是线程1是无法看到这个重排序的,因为这里有一个class对象的初始化锁,因为这里面有锁,对于线程0而言,初始化这个静态内部类的时候,也就是把这个instance new出来,可以看到我们这里还有一个大框,所以23怎么排序无所谓,线程1看不到,因为线程1在绿色区域等待着,所以静态内部类就是基于类初始化的延迟加载解决方案,那我们回到代码里
package com.learn.design.pattern.creational.singleton;/*** 前面说了我们使用静态内部类* * 所以静态内部类核心在于* InnerClass类的初始化锁* 看哪个线程拿到* 哪个线程就去初始化他* 对于这种情况呢* 我们来测试一下* 打开我们的线程类* 还是用多线程来测试* * 非常重要的一点* 我们没有写私有的构造函数* * * @author Leon.Sun**/
public class StaticInnerClassSingleton {/*** 这个class要声明成private的class* 权限一定要控制好* * * @author Leon.Sun**/private static class InnerClass{/*** 那这里声明一个什么呢* 这个名字还是用类名来做* new一个StaticInnerClassSingleton* 那在这个静态内部类里边直接new了一个StaticInnerClassSingleton这个类的对象* 并且它是private和static的* * */private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();}/*** 那我们要开放获取这个对象的方法* 所以是public的* 返回值肯定是StaticInnerClassSingleton* return什么呢* 通过这个静态内部类InnerClass点静态的成员staticInnerClassSingleton* 那这个静态内部类的单例模式就完成了* 非常简单* 那我们讲一下原理* 我们看一下图* * * @return*/public static StaticInnerClassSingleton getInstance(){return InnerClass.staticInnerClassSingleton;}/*** 私有的构造器肯定是要有的* 否则外部就可以new出来了* 所以这一点千万不要忘记* 如果之前写的时候没有发现这个问题的话* 对声明构造器一定要加深* 现在我们来到Test直接run一下* 我们可以看到线程0和线程1拿到的是同一个* 因为这个方式非常简单* 就不debug了* 静态内部类和签名的doublecheck* 都是为了做延迟初始化* 来降低创建单例实例的开销* 所以具体在业务场景中采用什么方案呢* 还要看我们的单例对象* 是什么样的* 另外一点* 如果问设计模式* 单例模式会被百分之九十九问到* 那么单例模式刚刚讲的这一种方案* 一定要理解透* 这个是一个循序渐进的过程* 而且单例模式非常重要* 如果可以一层一层迭代* 希望对着两种方案和思路来引入静态内部类和doublecheck一步一步解决什么问题* 可以自己回顾一下* 总结一下* * * */private StaticInnerClassSingleton(){if(InnerClass.staticInnerClassSingleton != null){throw new RuntimeException("单例构造器禁止反射调用");}}
}
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();/*** 通过这个类的getInstance方法* 看上去没有什么区别* 但是里面使用的是静态内部类* 而且是一个private的* */StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();;//        ContainerSingleton.putInstance("object",new Object());
//        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.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());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(String.class,int.class);
//
//        constructor.setAccessible(true);
//        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. 单例设计模式-静态内部类

    静态内部类 静态内部类应用实例 代码演示 package com.atguigu.principle.singleton.type07;/** * @author victor * @site htt ...

  2. 单例设计模式八种方式——5) 懒汉式(线程安全,同步代码块) 6) 双重检查 7) 静态内部类 8) 枚举

    懒汉式(线程安全,同步代码块)应用实例 优缺点说明: 1) 这种方式,本意是想对第四种实现方式的改进,因为前面同步方法效率太低, 改为同步产生实例化的的代码块 2) 但是这种同步并不能起到线程同步的作 ...

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

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

  4. 第 5 章 单例设计模式

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

  5. python单例设计模式(待补充)

    要点概论: 1. 理解单例设计模式 2. 单例模式中的懒汉式实例化 3. 模块级别的单例模式 4. Monostate单例模式 5. 单例和元类 6.单例模式Ⅰ 7. 单例模式Ⅱ 8. 单例模式的缺点 ...

  6. 高频面试题2:单例设计模式

    Singleton:在java中即指单例设计模式,某个类在整个系统中只能有一个实例对象可被获取和使用的代码模式.jvm中的runtime类. 1,只能有一个实例(构造器私有化) 2,必须自行创建这个实 ...

  7. IOS设计模式第二篇之单例设计模式

    现在我们的组件已经有组织了.你需要从其他的地方得到数据,你也可以创建一个API类管理数据这个下个设计模式单例里面介绍. 这个单例设计模式确保这个类仅仅拥有一个实例,并且为这个实例提供一个全局的访问点. ...

  8. java设计扑克牌比大小_2019-08-09Day10 单例设计模式,扑克牌比大小游戏(Java)

    目的 学习了解单例设计模式的相关知识,并在前几天Java学习的基础上,完善所学的知识,完成扑克牌比大小的游戏,能实现的功能有,游戏显示页面,玩家信息页面(包括玩家姓名 编号 所持有的资金),生成一副扑 ...

  9. 单例设计模式详解。。。。。。。。。。。

    public class Demo01 { public static void main(String[] args) { // TODO Auto-generated method stub /* ...

最新文章

  1. 【面试必问】支撑百万并发的IO多路复用技术你了解吗?
  2. 谁说程序员只能new对象?凭本事追的女神
  3. Nessus更新到8.3.0
  4. VMware虚拟机中,RHEL系统下挂载、卸载新硬盘的方法
  5. c# 建立到数据源的连接 以及获取项目配置文件的属性
  6. ConditionedActivityGroup
  7. 使用LiveNVR实现将RTSP转RTMP、FLV、HLS,实现监控摄像头无插件直播
  8. struts2和springmvc实现文件上传
  9. 探寻用户自定义定时任务的实践方案
  10. 事编计算机网络管理专技如何评级,事业单位管理和专技岗位有什么区别?哪个有前途?...
  11. sftp 服务器外网访问设置
  12. 欧拉角死锁_刚体运动学最通俗易懂的理解万向节死锁
  13. .NET基础 (03)生成、部署和管理
  14. AcWing 1402. 星空之夜 1月28
  15. 远程源已存在于“ git push”到新存储库中
  16. 大数据系统架构的通用模块有哪些
  17. 微信内置浏览器cookie设置问题
  18. grep正则表达式后面的单引号和双引号的区别?
  19. 穆利堂[推荐] WxPM信息化整体解决方案-河南郑州房地产工程项目管理系统软件 穆穆-movno1
  20. 求职迷茫?看看这篇为你准备的求职指北吧!

热门文章

  1. Windows server 2008 r2 开启Aero
  2. C#操作Excel的OLEDB方式与COM方式比较
  3. 程序员的进化(目前还看不懂)
  4. 设计模式笔记(19)---观察者模式(行为型)
  5. 对Coverage进行编辑
  6. mybatis 中 foreach collection的三种用法
  7. 技术人员如何创业《四》- 打造超强执行力团队(转载)
  8. 互动交流:移动系统安全研究专题及用户关心的焦点问题调研
  9. PAT、PMT、SDT详解
  10. LINK : fatal error LNK1104: cannot open file mfc42d.lib