在InstanceFactory示例代码中,符合情况4,InstanceHolder中静态字段instance被使用,导致触发InstanceHolder对象的初始化,从而初始化Instance对象。
在Java代码执行过程中,会存在多线程同时尝试去初始化一个类或者一个接口,因此在Java语言规范中,会要求具体的JVM实现对这个过程做同步处理。(实现规范是每个类或者接口有一个唯一的初始化锁LC与之对应。从C到LC的映射,由JVM去实现)。
5、Java初始化类或接口的具体过程
我们来看看《Java并发编程艺术》的作者是如何通过5个步骤阐述这个过程的。
5.1 第一阶段
通过在Class对象上同步(获取Class对象的初始化锁),来控制类或接口的初始化。这个获取锁的线程会一直等待,知道当前线程能够获取到这个Class对象的初始化锁。
假设线程A和线程B同时初始化一个未被初始化的Class对象(初始化状态state,此时被标记为state=noInitialization),图示如下:
类初始化-第一阶段
类初始化-第一阶段执行时序表:
| 时间 | 线程A | 线程B |
| — | — | — |
| t1 | A1:尝试获取Class对象的初始化锁。这里假设线程A获取到初始化锁。 | B1:尝试获取Class对象的初始化锁,由于线程A获取到了锁,线程B等待获取初始化锁 |
| t2 | A2:线程A看到对象还未被初始化(state=noInitialization),线程设置state=noInitializating | |
| t3 | A3:线程A释放初始化锁 | |
5.2 第二阶段
线程A执行类的初始化,同时线程B在初始锁对应的condition上等待。
图示如下:
类初始化-第2阶段
类初始化-第二阶段执行时序表:
| 时间 | 线程A | 线程B |
| — | — | — |
| t1 | A1:执行类的静态初始化和初始化类中声明的静态字段 | B1:获取到初始化锁 |
| t2 | | B2:读取到state=initializing |
| t3 | | B3:释放初始化锁 |
| t4 | | B4:在初始化锁的condition中等待 |
5.3 第三阶段
线程A设置state=initialized,然后唤醒等待在condition上的所有线程
类初始化-第3阶段
类初始化-第三阶段执行时序表:
| 时间 | 线程A |
| — | — |
| t1 | A1:获取初始化锁 |
| t2 | A2:设置state=initialized |
| t3 | A3:唤醒在condition中等待的所有线程 |
| t4 | A4:释放初始化锁 |
| t5 | A5:线程A的初始化过程完成 |
5.4 第四阶段
线程B结束类的初始化处理
类初始化-第4阶段
类初始化-第四阶段执行时序表:
| 时间 | 线程B |
| — | — |
| t1 | B1:获取初始化锁 |
| t2 | B2:读取到state=initialized |
| t3 | B3:释放初始化锁 |
| t4 | B4:线程B的类的初始化过程完成 |
第五阶段
线程C执行类的初始化处理
类初始化-第5阶段
类初始化-第五阶段执行时序表:
| 时间 | 线程C |
| — | — |
| t1 | C1:获取初始化锁 |
| t2 | C2:读取到state=initialized |
| t3 | C3:释放初始化锁 |
| t4 | C4:线程B的类的初始化过程完成 |
由于在第三阶段已经完成了类的初始化,因此线程C执行类的初始化过程相对简单。
6、总结
通过对比基于volatile的双重锁定的方案和基于类初始化的方案,发现使用类初始化的方案实现的代码更加简洁。但是基于volatile的双重检查锁定的方案有一个额外的优点就是其不仅可以对静态字段实现延迟初始化,也可以对实例字段实现延迟初始化(因为JVM类初始化这个方案只能初始化静态字段)。字段延迟初始化降低了初始化类和创建实例带来的开销,但也增加了访问被延迟初始化的字段的开销。而在实际开发中正常的初始化要优于延迟初始化。
如果确定要进行延迟初始化,那么具体如何选择呢?
-
实例字段延迟初始化使用volatile方案
-
静态字段延迟初始化使用类初始化方案
文章总结至《Java并发编程艺术》,Java内存模型的总结到此就完全结束了,花费了不少晚上。虽然文章知识点来自书本,但是作者也做了如下工作:
-
文章的重点知识做了梳理和标记
-
对黑白图片做了彩色画图,使其更加易懂
-
对部分繁琐的知识点做了概括
-
对少部分错误的知识(主要是错字)进行了勘误
-
对每一句代码做了全部重写和注释
码字不易,多多关注。
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
总结
以上是字节二面的一些问题,面完之后其实挺后悔的,没有提前把各个知识点都复习到位。现在重新好好复习手上的面试大全资料(含JAVA、MySQL、算法、Redis、JVM、架构、中间件、RabbitMQ、设计模式、Spring等),现在起闭关修炼半个月,争取早日上岸!!!
下面给大家分享下我的面试大全资料
- 第一份是我的后端JAVA面试大全
后端JAVA面试大全
- 第二份是MySQL+Redis学习笔记+算法+JVM+JAVA核心知识整理
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理
- 第三份是Spring全家桶资料
MySQL+Redis学习笔记算法+JVM+JAVA核心知识整理
一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算
这里加入程序员的圈子,让我们一起学习成长!**](https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0)
AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算