- 为什么ArrayList不是线程安全的,具体来说是哪里不安全?
2. 比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同
HashMap 的底层实现
HashMap 的长度为什么是 2 的幂次方
列举HashMap在多线程下可能会出现的问题?
7. ConcurrentHashMap 和 Hashtable 的区别
- ConcurrentHashMap已经用了synchronized,为什么还要用CAS(乐观锁)呢
为什么HashMap要用红黑树而不是平衡二叉树?
HashMap的扩容机制介绍一下
请简要描述线程与进程的关系,区别及优缺点?
- 说说线程的生命周期和状态?
7. Thread#sleep() 方法和 Object#wait() 方法对比
- 可以直接调用 Thread 类的 run 方法吗?
4. synchronized 和 volatile 有什么区别?
synchronized 和 ReentrantLock 有什么区别?
ThreadLocal 内存泄露问题是怎么导致的?如何避免?
start启动线程,线程池:submit对于callable,execute对于runable。
3. 一个任务需要依赖另外两个任务执行完之后再执行,怎么设计?
死亡对象判断方法
如何判断一个类是无用的类?
垃圾收集器
类加载过程
JVM 中内置了三个重要的 ClassLoader
类加载器和双亲委派机制。
1. 说说自己对于 Spring MVC 了解?
MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码。
3. 将一个类声明为 Bean 的注解有哪些?
@Component:通用的注解,可标注任意类为Spring组件。如果一个 Bean 不知道属于哪个层,可以使用@Component注解标注。@Repository: 对应持久层即 Dao 层,主要用于数据库相关操作。@Service: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。@Controller: 对应 Spring MVC 控制层,主要用于接受用户请求并调用Service层返回数据给前端页面。
11. Bean 的生命周期了解么?
创建 Bean 的实例:Bean 容器首先会找到配置文件中的 Bean 定义,然后使用 Java 反射 API 来创建 Bean 的实例。
Bean 属性赋值/填充:为 Bean 设置相关属性和依赖,例如
@Autowired等注解注入的对象、@Value注入的值、setter方法或构造函数注入依赖和值、@Resource注入的各种资源。Bean 初始化
- 如果 Bean 实现了
BeanNameAware接口,调用setBeanName()方法,传入 Bean 的名字。 - 如果 Bean 实现了
BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。 - 如果 Bean 实现了
BeanFactoryAware接口,调用setBeanFactory()方法,传入BeanFactory对象的实例。 - 与上面的类似,如果实现了其他
*.Aware接口,就调用相应的方法。 - 如果有和加载这个 Bean 的 Spring 容器相关的
BeanPostProcessor对象,执行postProcessBeforeInitialization()方法 - 如果 Bean 实现了
InitializingBean接口,执行afterPropertiesSet()方法。 - 如果 Bean 在配置文件中的定义包含
init-method属性,执行指定的方法。 - 如果有和加载这个 Bean 的 Spring 容器相关的
BeanPostProcessor对象,执行postProcessAfterInitialization()方法。
- 如果 Bean 实现了
销毁 Bean
:销毁并不是说要立马把 Bean 给销毁掉,而是把 Bean 的销毁方法先记录下来,将来需要销毁 Bean 或者销毁容器的时候,就调用这些方法去释放 Bean 所持有的资源。
- 如果 Bean 实现了
DisposableBean接口,执行destroy()方法。 - 如果 Bean 在配置文件中的定义包含
destroy-method属性,执行指定的 Bean 销毁方法。或者,也可以直接通过@PreDestroy注解标记 Bean 销毁之前执行的方法。
- 如果 Bean 实现了
整体上可以简单分为四步:实例化 —> 属性赋值 —> 初始化 —> 销毁。
初始化这一步涉及到的步骤比较多,包含
Aware接口的依赖注入、BeanPostProcessor在初始化前后的处理以及InitializingBean和init-method的初始化操作。销毁这一步会注册相关销毁回调接口,最后通过
DisposableBean和destory-method进行销毁。

3. SpringMVC 工作原理了解吗?
- 客户端(浏览器)发送请求,
DispatcherServlet拦截请求。 DispatcherServlet根据请求信息调用HandlerMapping。HandlerMapping根据 URL 去匹配查找能处理的Handler(也就是我们平常说的Controller控制器) ,并会将请求涉及到的拦截器和Handler一起封装。DispatcherServlet调用HandlerAdapter适配器执行Handler。Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。Model是返回的数据对象,View是个逻辑上的View。ViewResolver会根据逻辑View查找实际的View。DispaterServlet把返回的Model传给View(视图渲染)。- 把
View返回给请求者(浏览器)

上述流程是传统开发模式(JSP,Thymeleaf 等)的工作原理。
对于前后端分离时,后端通常不再返回具体的视图,而是返回纯数据(通常是 JSON 格式,Spring 会自动将其转换为 JSON 格式),由前端负责渲染和展示。
1. Spring 循环依赖了解吗,怎么解决?
两个或多个 Bean 之间相互持有对方的引用。
@Component
public class CircularDependencyA {
@Autowired
private CircularDependencyB circB;
}
@Component
public class CircularDependencyB {
@Autowired
private CircularDependencyA circA;
}
有三级缓存:
- 一级缓存(singletonObjects):存放最终形态的 Bean(已经实例化、属性填充、初始化),单例池,为“Spring 的单例属性”⽽⽣。一般情况我们获取 Bean 都是从这里获取的,但是并不是所有的 Bean 都在单例池里面,例如原型 Bean 就不在里面。
- 二级缓存(earlySingletonObjects):存放过渡 Bean(半成品,尚未属性填充,未进行依赖注入),也就是三级缓存中
ObjectFactory产生的对象,与三级缓存配合使用的,可以防止 AOP 的情况下,每次调用ObjectFactory#getObject()都是会产生新的代理对象的。 - 三级缓存(singletonFactories):存放
ObjectFactory,ObjectFactory的getObject()方法(最终调用的是getEarlyBeanReference()方法)可以生成原始 Bean 对象或者代理对象(如果 Bean 被 AOP 切面代理)。三级缓存只会对单例 Bean 生效。
- 先去 一级缓存
singletonObjects中获取,存在就返回; - 如果不存在或者对象正在创建中,于是去 二级缓存
earlySingletonObjects中获取; - 如果还没有获取到,就去 三级缓存
singletonFactories中获取,通过执行ObjectFacotry的getObject()就可以获取该对象,获取成功之后,从三级缓存移除B,并将B对象加入到二级缓存中。
步骤 1:创建 Bean A
- Spring 容器开始创建 Bean A,首先将 Bean A 的创建状态标记为 “正在创建”。
- 实例化 Bean A,将 Bean A 的早期引用(一个
ObjectFactory对象)放入三级缓存singletonFactories中。这个ObjectFactory对象可以在需要时返回 Bean A 的早期实例。 - 开始对 Bean A 进行属性注入,发现 Bean A 依赖于 Bean B。
步骤 2:创建 Bean B
- Spring 容器开始创建 Bean B,同样将 Bean B 的创建状态标记为 “正在创建”。
- 实例化 Bean B,将 Bean B 的早期引用放入三级缓存
singletonFactories中。 - 开始对 Bean B 进行属性注入,发现 Bean B 依赖于 Bean A。
步骤 3:解决 Bean B 对 Bean A 的依赖
- 当 Bean B 需要注入 Bean A 时,Spring 容器首先从一级缓存
singletonObjects中查找 Bean A,发现没有找到。 - 接着从二级缓存
earlySingletonObjects中查找,也没有找到。 - 然后从三级缓存
singletonFactories中查找,找到了 Bean A 的早期引用(ObjectFactory对象)。 - 调用
ObjectFactory的getObject()方法,获取 Bean A 的早期实例。如果 Bean A 需要进行 AOP 代理,会在这里创建代理对象,并将代理对象放入二级缓存earlySingletonObjects中,同时从三级缓存singletonFactories中移除该引用。 - 将获取到的 Bean A 的早期实例注入到 Bean B 中。
步骤 4:完成 Bean B 的创建
- Bean B 完成属性注入后,进行初始化操作。
- 将完全创建好的 Bean B 实例放入一级缓存
singletonObjects中,并从二级缓存earlySingletonObjects和三级缓存singletonFactories中移除相关引用。
步骤 5:完成 Bean A 的创建
- 由于 Bean B 已经创建完成,将 Bean B 实例注入到 Bean A 中。
- Bean A 完成属性注入后,进行初始化操作。
- 将完全创建好的 Bean A 实例放入一级缓存
singletonObjects中,并从二级缓存earlySingletonObjects和三级缓存singletonFactories中移除相关引用。
1. 什么是 Spring Boot Starters?
Spring Boot Starters 是一组便捷的依赖描述符,它们预先打包了常用的库和配置。当我们开发 Spring 应用时,只需添加一个 Starter 依赖项,即可自动引入所有必要的库和配置,快速引入相关功能。
在没有 Spring Boot Starters 之前,开发一个 RESTful 服务或 Web 应用程序通常需要手动添加多个依赖,比如 Spring MVC、Tomcat、Jackson 等。这不仅繁琐,还容易导致版本不兼容的问题。而有了 Spring Boot Starters,我们只需添加一个依赖,如 spring-boot-starter-web,即可包含所有开发 REST 服务所需的库和依赖。
这个 spring-boot-starter-web 依赖包含了 Spring MVC(用于处理 Web 请求)、Tomcat(默认嵌入式服务器)、Jackson(用于 JSON 处理)等依赖项。这种方式极大地简化了开发过程,让我们可以更加专注于业务逻辑的实现。
2. 介绍一下@SpringBootApplication 注解
- @EnableAutoConfiguration: 启用 Spring Boot 的自动配置机制。它是自动配置的核心,允许 Spring Boot 根据项目的依赖和配置自动配置 Spring 应用的各个部分。
- @ComponentScan: 启用组件扫描,扫描被 @Component(以及 @Service、@Controller 等)注解的类,并将这些类注册为 Spring 容器中的 Bean。默认情况下,它会扫描该类所在包及其子包下的所有类。
- @Configuration: 允许在上下文中注册额外的 Bean 或导入其他配置类。它相当于一个具有 @Bean 方法的 Spring 配置类。
3. Spring Boot 的自动配置是如何实现的?
Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配.
HTTP和HTTPS二者区别
- HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
- HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
- 两者的默认端口不一样,HTTP 默认端口号是 80,HTTPS 默认端口号是 443。
- HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。
对称+非对称、摘要算法+数字签名、身份证书
TCP、UDP区别、应用场景
MySQL 基础架构
1. 结构
- 连接器: 身份认证和权限相关(登录 MySQL 的时候)。
- 查询缓存: 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
- 分析器: 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。
- 优化器: 按照 MySQL 认为最优的方案去执行。
- 执行器: 执行语句,然后从存储引擎返回数据。 执行语句之前会先判断是否有权限,如果没有权限的话,就会报错。
- 插件式存储引擎:主要负责数据的存储和读取,采用的是插件式架构,支持 InnoDB、MyISAM、Memory 等多种存储引擎。InnoDB 是 MySQL 的默认存储引擎,绝大部分场景使用 InnoDB 就是最好的选择。

2. SQL语句在MySQL中的执行过程
- 查询语句的执行流程如下:权限校验(如果命中缓存)--->查询缓存--->分析器--->优化器--->权限校验--->执行器--->引擎
- 更新语句执行流程如下:分析器---->权限校验---->执行器--->引擎---redo log(prepare 状态)--->binlog--->redo log(commit 状态)