面经 - Java 中级进阶面试题
Posted 程序员牧码
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面经 - Java 中级进阶面试题相关的知识,希望对你有一定的参考价值。
1、什么是 Spring Boot?
解析:SpringBoot是Spring开源组织下的子项目,是Spring组件一站式处理方案,主要是简化了使用Spring的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。
2、为什么要用 Spring Boot?
解析:SpringBoot优点非常多,如:
- 独立运行
- 简化配置
- 自动配置
- 无代码生成和XML配置
- 应用监控
- 上手容易.....
- SpringBoot集这么多优点于一身,还有理由不使用它呢?
3、Spring Boot 的核心配置文件有哪几个?它们的区别是什么?
解析:
- SpringBoot的核心配置文件是application和bootstrap配置文件
- application配置文件这个容易了解,主要用于SpringBoot项目的自动化配置
- bootstrap配置文件有以下几个应用场景
- 使用SpringCloudConfig配置中心时,这时需要在bootstrap配置文件中增加连接到配置中心的配置属性来加载外部配置中心的配置信息
- 少量固定的不能被覆盖的属性
- 少量加密/解密的场景
4、Spring Boot 的配置文件有哪几种格式?它们有什么区别?
解析:.properties和.yml,它们的区别主要是书写格式不同
1).properties
2).yml
另外,.yml格式不支持@PropertySource注解导入配置
5、Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
解析:启动类上面的注解是@SpringBootApplication,它也是SpringBoot的核心注解,主要组合包含了以下 3 个注解:
- @SpringBootConfiguration:组合了@Configuration注解,实现配置文件的功能。
- @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能:@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})。
- @ComponentScan:Spring组件扫描。
6、开启 Spring Boot 特性有哪几种方式?
解析:
(1)继承spring-boot-starter-parent项目
(2)导入spring-boot-dependencies项目依赖
7、Spring Boot 需要独立的容器运行吗?
解析:可以不需要,内置了 Tomcat / Jetty 等容器。
8、运行 Spring Boot 有哪几种方式?
解析:
(1)打包用命令或者者放到容器中运行
(2)用Maven/Gradle插件运行
(3)直接执行main方法运行
9、SpringBoot 常用的 starter 有哪些?
解析:
- spring-boot-starter-web 嵌入 tomcat 和 web 开发需要 servlet 与 jsp 支持
- spring-boot-starter-data-jpa 数据库支持
- spring-boot-starter-data-redisredis 数据库支持
- spring-boot-starter-data-solr solr 支持
- mybatis-spring-boot-starter 第三方的 mybatis 集成 starter
10、Spring Boot 自动配置原理是什么?
解析:注解@EnableAutoConfiguration,@Configuration,@ConditionalOnClass就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下能否有这个类去自动配置。
11、你如何了解 Spring Boot 中的 Starters?
解析:Starters可以了解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成Spring及其余技术,而不需要四处找示例代码和依赖包。
如你想使用SpringJPA访问数据库,只需加入spring-boot-starter-data-jpa启动器依赖就能使用了。
Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。
12、如何在 Spring Boot 启动的时候运行少量特定的代码?
解析:可以实现接口ApplicationRunner或者者CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个run方法。
13、Spring Boot 有哪几种读取配置的方式?
解析:Spring Boot 可以通过 @PropertySource、@Value、@Environment、@ConfigurationProperties 来绑定变量。
14、Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?
解析:SpringBoot支持JavaUtilLogging、Log4j2、Lockback作为日志框架,假如你使用Starters启动器,SpringBoot将使用Logback作为默认日志框架。
15、SpringBoot 实现热部署有哪几种方式?
解析:主要有两种方式:Spring Loaded、Spring-boot-devtools。
16、你如何了解 Spring Boot 配置加载顺序?
解析:在 Spring Boot 里面,可以使用以下几种方式来加载配置。
1)properties文件
2)YAML文件
3)系统环境变量
4)命令行参数等等
17、SpringBoot可以兼容老Spring项目吗,如何做?
解析:可以兼容,使用@ImportResource注解导入老Spring项目配置文件。
18、保护 Spring Boot 应用有哪些方法?
解析:
- 在生产中使用HTTPS
- 使用Snyk检查你的依赖关系
- 更新到最新版本
- 启用CSRF保护
- 使用内容安全策略防止XSS攻击...
19、Spring Boot 2.X 有什么新特性?与 1.X 有什么区别?
解析:
- 配置变更
- JDK 版本更新
- 第三方类库更新
- 响应式 Spring 编程支持
- HTTP/2 支持
- 配置属性绑定
- 更多改进与增强…
20、什么是Spring Profiles?
解析:SpringProfiles允许用户根据配置文件(dev,test,prod等)来注册bean。
因此,当应用程序在开发中运行时,只有某些bean可以加载,而在PRODUCTION中,某些其他bean可以加载。
假设我们的要求是Swagger文档仅适用于QA环境,并且禁用所有其他文档。这可以使用配置文件来完成。SpringBoot使得使用配置文件非常简单。
21、什么是Spring Batch?
解析:SpringBootBatch提供可重用的函数,这些函数在处理大量记录时非常重要,包括日志/跟踪,事务管理,作业处理统计信息,作业重新启动,跳过和资源管理。
它还提供了更先进的技术服务和功能,通过优化和分区技术,可以实现极高批量和高性能批处理作业。
简单以及复杂的大批量批处理作业可以高度可扩展的方式利用框架处理重要大量的信息。
22、什么是FreeMarker模板?
解析:FreeMarker是一个基于Java的模板引擎,最初专注于使用MVC软件架构进行动态网页生成。使用 Freemarker的主要优点是表示层和业务层的完全分离。
程序员可以处理应用程序代码,而设计人员可以处理html页面设计。最后使用freemarker可以将这些 结合起来,给出最终的输出页面。
23、什么是JavaConfig?
解析:SpringJavaConfig是Spring社区的产品,它提供了配置SpringIoC容器的纯Java方法。因此它有助于避免使用XML配置。
使用JavaConfig的优点在于:
面向对象的配置。由于配置被定义为JavaConfig中的类,因此用户可以充分利用Java中的面向对象功能。一个配置类可以继承另一个,重写它的@Bean方法等。
减少或消除XML配置。基于依赖注入原则的外化配置的好处已被证明。但是,许多开发人员不希望在XML和Java之间来回切换。
JavaConfig为开发人员提供了一种纯Java方法来配置与XML配置概念相似的Spring容器。
从技术角度来讲,只使用JavaConfig配置类来配置容器是可行的,但实际上很多人认为将JavaConfig与XML混合匹配是理想的。
类型安全和重构友好。JavaConfig提供了一种类型安全的方法来配置Spring容器。由于Java5.0对泛型的支持,现在可以按类型而不是按名称检索bean,不需要任何强制转换或基于字符串的查找。
24、启动类注解?
解析:@SpringBootConfiguration:SpringBoot的配置类;标注在某个类上,表示这是一个SpringBoot的配置类;@Configuration:配置类上来标注这个注解
配置类-----配置文件;配置类也是容器中的一个组件;@Component@EnableAutoConfiguration:开启自动配置功能
以前我们需要配置的东西,SpringBoot帮我们自动配置;@EnableAutoConfiguration告SpringBoot开启自动配置功能;这样自动配置才能生效
SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。
25、配置文件的加载顺序?
解析:Spring Boot为了能够更合理的重写各属性的值,提供了下面17种配置管理方式(数字越小优先级越高)
- 当$HOME/.config/spring-boot目录下的devtools是启用状态时,会使用Devtools全局设置配置
- 单元测试中的@TestPropertySource的注解
- 单元测试中的properties属性. 测试注解@SpringBootTest以及应用启用的其他测试注解.
- 命令行中传入的参数
- SPRING_APPLICATION_JSON中的属性。SPRING_APPLICATION_JSON是以JSON格式配置在系统环境变量中的内容
- ServletConfig初始化的参数
- ServletContext初始化的参数
- java:comp/env中的JNDI属性
- Java的系统属性 (System.getProperties())
- 操作系统的环境变量
- 通过random.*配置的随机属性
- 位于当前应用jar包之外,指定了不同{profile}环境的application-{profile}.properties/yml配置文件
- 位于当前应用jar包之内,指定了不同{profile}环境的application-{profile}.properties/yml配置文件
- 位于当前应用jar包之外的application-{profile}.properties/yml配置文件
- 位于当前应用jar包之内的application-{profile}.properties/yml配置文件
- 在@Configuration注解修改的类中,通过@PropertySource注解定义的属性
- 应用默认属性,使用SpringApplication.setDefaultProperties定义的内容
26、自动配置原理?
解析:
(1)SpringBoot启动的时候加载主配置类,开启了自动配置功能@EnableAutoConfiguration
(2)@EnableAutoConfiguration作用:将类路径下META-INF/spring.factories里面配置的所有
EnableAutoConfiguration的值加入到了容器中;每一个这样的xxxAutoConfiguration类都是容器中的一个组件,都加入到容器中;用他们来做自动配置
(3)每一个自动配置类进行自动配置功能;根据当前不同的条件判断,决定这个配置类是否生效?一但这个配置类生效;这个配置类就会给容器中添加各种组件;这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的
(4)所有在配置文件中能配置的属性都是在xxxxProperties类中封装者‘;配置文件能配置什么就可以参照某个功能对应的这个属性类怎么用好自动配置,精髓:
i)SpringBoot启动会加载大量的自动配置类
ii)我们看我们需要的功能有没有SpringBoot默认写好的自动配置类
iii)我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)
iv)给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值
27、什么是 Spring Cloud?
解析:SpringCloud是一系列框架的有序集合。它利用SpringBoot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用SpringBoot的开发风格做到一键启动和部署。
28、Spring Cloud 断路器的作用是什么?
解析:在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延。
29、Spring Cloud 的核心组件有哪些?
解析:Eureka:服务注册于发现。Feign:基于动态代理机制,根据注解和选择的机器,拼接请求url地址,发起请求。Ribbon:实现负载均衡,从一个服务的多台机器中选择一台。
Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。
Zuul:网关管理,由Zuul网关转发请求给对应的服务。
30、SpringCloud 和 Dubbo?
解析:SpringCloud和Dubbo都是现在主流的微服务架构
SpringCloud是Apache旗下的Spring体系下的微服务解决方案
Dubbo是阿里系的分布式服务治理框架
从技术维度上,其实SpringCloud远远的超过Dubbo,Dubbo本身只是实现了服务治理,而SpringCloud现在以及有21个子项目以后还会更多
所以其实很多人都会说Dubbo和SpringCloud是不公平的
但是由于RPC以及注册中心元数据等原因,在技术选型的时候我们只能二者选其一,所以我们常常为用他俩来对比
服务的调用方式Dubbo使用的是RPC远程调用,而SpringCloud使用的是RestAPI,其实更符合微服务官方的定义
服务的注册中心来看,Dubbo使用了第三方的ZooKeeper作为其底层的注册中心,实现服务的注册和发现,SpringCloud使用SpringCloudNetflixEureka实现注册中心,当然SpringCloud也可以使用ZooKeeper实现,但一般我们不会这样做
服务网关,Dubbo并没有本身的实现,只能通过其他第三方技术的整合,而SpringCloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,SpringCloud还支持断路器,与git完美集成分布式配置文件支持版本控制,事务总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素
从技术选型上讲
目前国内的分布式系统选型主要还是Dubbo毕竟国产,而且国内工程师的技术熟练程度高,并且Dubbo在其他维度上的缺陷可以由其他第三方框架进行集成进行弥补
而SpringCloud目前是国外比较流行,当然我觉得国内的市场也会慢慢的偏向SpringCloud,就连刘军作为Dubbo重启的负责人也发表过观点,Dubbo的发展方向是积极适应SpringCloud生态,并不是起冲突
Rest和RPC对比
其实如果仔细阅读过微服务提出者马丁福勒的论文的话可以发现其定义的服务间通信机制就是HttpRest
RPC最主要的缺陷就是服务提供方和调用方式之间依赖太强,我们需要为每一个微服务进行接口的定义,并通过持续继承发布,需要严格的版本控制才不会出现服务提供和调用之间因为版本不同而产生的冲突
而REST是轻量级的接口,服务的提供和调用不存在代码之间的耦合,只是通过一个约定进行规范,但也有可能出现文档和接口不一致而导致的服务集成问题,但可以通过swagger工具整合,是代码和文档一体化解决,所以REST在分布式环境下比RPC更加灵活
这也是为什么当当网的DubboX在对Dubbo的增强中增加了对REST的支持的原因
文档质量和社区活跃度
SpringCloud社区活跃度远高于Dubbo,毕竟由于梁飞团队的原因导致Dubbo停止更新迭代五年,而中小型公司无法承担技术开发的成本导致Dubbo社区严重低落,而SpringCloud异军突起,迅速占领了微服务的市场,背靠Spring混的风生水起
Dubbo经过多年的积累文档相当成熟,对于微服务的架构体系各个公司也有稳定的现状
31、SpringBoot 和 SpringCloud?
解析:SpringBoot是Spring推出用于解决传统框架配置文件冗余,装配组件繁杂的基于Maven的解决方案,旨在快速搭建单个微服务
而SpringCloud专注于解决各个微服务之间的协调与配置,服务之间的通信,熔断,负载均衡等
技术维度并相同,并且SpringCloud是依赖于SpringBoot的,而SpringBoot并不是依赖与SpringCloud,甚至还可以和Dubbo进行优秀的整合开发
总结
SpringBoot专注于快速方便的开发单个个体的微服务
SpringCloud是关注全局的微服务协调整理治理框架,整合并管理各个微服务,为各个微服务之间提供,配置管理,服务发现,断路器,路由,事件总线等集成服务
SpringBoot不依赖于SpringCloud,SpringCloud依赖于SpringBoot,属于依赖关系
SpringBoot专注于快速,方便的开发单个的微服务个体,SpringCloud关注全局的服务治理框架
32、Eureka和ZooKeeper都可以提供服务注册与发现的功能,请说说两个的区别?
解析:
1、ZooKeeper保证的是CP,Eureka保证的是AP
ZooKeeper在选举期间注册服务瘫痪,虽然服务最终会恢复,但是选举期间不可用的
Eureka各个节点是平等关系,只要有一台Eureka就可以保证服务可用,而查询到的数据并不是最新的
自我保护机制会导致
Eureka不再从注册列表移除因长时间没收到心跳而应该过期的服务
Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点(高可用)
当网络稳定时,当前实例新的注册信息会被同步到其他节点中(最终一致性)
Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像ZooKeeper一样使得整个注册系统瘫痪
2、ZooKeeper有Leader和Follower角色,Eureka各个节点平等
3、ZooKeeper采用过半数存活原则,Eureka采用自我保护机制解决分区问题
4、Eureka本质上是一个工程,而ZooKeeper只是一个进程
33、微服务之间是如何独立通讯的?
解析:
1、远程过程调用(RemoteProcedureInvocation)
也就是我们常说的服务的注册与发现
直接通过远程过程调用来访问别的service。
优点:简单,常见,因为没有中间件代理,系统更简单
缺点:只支持请求/响应的模式,不支持别的,比如通知、请求/异步响应、发布/订阅、发布/异步响应降低了可用性,因为客户端和服务端在请求过程中必须都是可用的
2、消息
使用异步消息来做服务间通信。服务间通过消息管道来交换消息,从而通信。
优点
把客户端和服务端解耦,更松耦合
提高可用性,因为消息中间件缓存了消息,直到消费者可以消费
支持很多通信机制比如通知、请求/异步响应、发布/订阅、发布/异步响应
缺点
消息中间件有额外的复杂
34、什么是服务熔断?什么是服务降级?
解析:在复杂的分布式系统中,微服务之间的相互调用,有可能出现各种各样的原因导致服务的阻塞,在高并发场景下,服务的阻塞意味着线程的阻塞,导致当前线程不可用,服务器的线程全部阻塞,导致服务器崩溃,由于服务之间的调用关系是同步的,会对整个微服务系统造成服务雪崩。
为了解决某个微服务的调用响应时间过长或者不可用进而占用越来越多的系统资源引起雪崩效应就需要进行服务熔断和服务降级处理。
所谓的服务熔断指的是某个服务故障或异常一起类似显示世界中的“保险丝"当某个异常条件被触发就直接熔断整个服务,而不是一直等到此服务超时。
服务熔断就是相当于我们电闸的保险丝,一旦发生服务雪崩的,就会熔断整个服务,通过维护一个自己的线程池,当线程达到阈值的时候就启动服务降级,如果其他请求继续访问就直接返回fallback的默认值。
35、微服务的优缺点分别是什么?说下你在项目开发中碰到的坑?
解析:
优点
每一个服务足够内聚,代码容易理解
开发效率提高,一个服务只做一件事
微服务能够被小团队单独开发
微服务是松耦合的,是有功能意义的服务
可以用不同的语言开发,面向接口编程
易于与第三方集成
微服务只是业务逻辑的代码,不会和HTML,CSS或者其他界面组合
开发中,两种开发模式:前后端分离,全栈工程师
可以灵活搭配,连接公共库/连接独立库
缺点
分布式系统的负责性
多服务运维难度,随着服务的增加,运维的压力也在增大
系统部署依赖
服务间通信成本
数据一致性
系统集成测试
性能监控
36、什么是 Spring?
解析:Spring是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。
37、使用Spring框架的好处是什么?
解析:轻量:Spring是轻量的,基本的版本大约2MB。
控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。
面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
容器:Spring包含并管理应用中对象的生命周期和配置。
MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
事务管理:Spring提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
异常处理:Spring提供方便的API把具体技术相关的异常(比如由JDBC,HibernateorJDO抛出的)转化为一致的unchecked异常。
38、解释一下什么是 AOP?
解析:AOP是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。简单来说就是统一处理某一“切面”(类)的问题的编程思想,比如统一处理日志、异常等。
39、解释一下什么是 IOC?
解析:IOC:Inversion of control(中文:控制反转)是spring的核心,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系。
简单来说,控制指的是当前对象对内部成员的控制权;控制反转指的是,这种控制权不由当前对象管理了,由其他(类,第三方容器)来管理。
40、Spring 有哪些主要模块?
解析:spring core:框架的最基础部分,提供ioc和依赖注入特性。
spring context:构建于core封装包基础上的context封装包,提供了一种框架式的对象访问方法。
spring dao:DataAccessObject提供了JDBC的抽象层。
spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
spring web:提供了针对Web开发的集成特性,例如文件上传,利用servletlisteners进行ioc容器初始化和针对Web的ApplicationContext。
springWebmvc:spring中的mvc封装包提供了Web应用的Model-View-Controller(MVC)的实现。
41、Spring 常用的注入方式有哪些?
解析:Setter 属性注入、构造方法注入、注解方式注入。
42、Spring 中的 Bean 是线程安全的吗?
解析:spring中的bean默认是单例模式,spring框架并没有对单例bean进行多线程的封装处理。
实际上大部分时候springbean无状态的(比如 dao 类),所有某种程度上来说bean也是安全的,但如果bean有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变bean的作用域,把“singleton”变更为“prototype”,这样请求bean相当于newBean()了,所以就可以保证线程安全了。
有状态就是有数据存储功能。
无状态就是不会保存数据。
43、Spring 支持几种 Bean 的作用域?
解析:Spring支持5种作用域,如下:
singleton:springioc容器中只存在一个bean实例,bean以单例模式存在,是系统默认值;
prototype:每次从容器调用bean时都会创建一个新的示例,既每次getBean()相当于执行newBean()操作;
Web环境下的作用域:
request:每次http请求都会创建一个bean;
session:同一个httpsession共享一个bean实例;
global-session:用于portlet容器,因为每个portlet有单独的session,globalsession提供一个全局性的httpsession。
注意:使用prototype作用域需要慎重的思考,因为频繁创建和销毁bean会带来很大的性能开销。
44、Spring 自动装配 Bean 有哪些方式?
解析:no:默认值,表示没有自动装配,应使用显式bean引用进行装配。
byName:它根据bean的名称注入对象依赖项。
byType:它根据类型注入对象依赖项。
构造函数:通过构造函数来注入依赖项,需要设置大量的参数。
autodetect:容器首先通过构造函数使用autowire装配,如果不能,则通过byType自动装配。
45、Spring 事务实现方式有哪些?
解析:声明式事务:声明式事务也有两种实现方式,基于xml配置文件的方式和注解方式(在类上添加 @Transaction 注解)。
编码方式:提供编码的形式管理和维护事务。
46、说一下 Spring 的事务隔离?
解析:Spring有五大隔离级别,默认值为ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:
- ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
- ISOLATION_READUNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
- ISOLATION_READCOMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server的默认级别;
- ISOLATION_REPEATABLEREAD:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),mysql 的默认级别;
- ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
- 脏读:表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
- 不可重复读 :是指在一个事务内,多次读同一数据。
- 幻读:指同一个事务内多次查询返回的结果集不一样。比如同一个事务A第一次查询时候有n条记录,但是第二次同等条件下查询却有n+1条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。
47、什么是 Spring 的 MVC 框架?
解析:Spring配备构建Web应用的全功能MVC框架。Spring可以很便捷地和其他MVC框架集成,如Struts,Spring的MVC框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。
48、说一下 Spring MVC 运行流程?
解析:Spring MVC 先将请求发送给 DispatcherServlet。
DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller。
DispatcherServlet再把请求提交到对应的Controller。
Controller进行业务逻辑处理后,会返回一个ModelAndView。
Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象。
视图对象负责渲染返回给客户端。
49、Spring MVC 有哪些组件?
解析:前置控制器DispatcherServlet。
映射控制器HandlerMapping。
处理器Controller。
模型和视图ModelAndView。
视图解析器ViewResolver。
50、@Autowired 和 @Resource 的区别?
解析:@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配。
@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了。
Spring属于第三方的,J2EE是Java自己的东西,因此,建议使用@Resource注解,以减少代码和Spring之间的耦合。
51、为什么要使用线程池?
解析:避免频繁地创建和销毁线程,达到线程对象的重用。另外,使用线程池还可以根据项目灵活地控制并发的数目。
52、Java中如何获取到线程dump文件?
解析:死循环、死锁、阻塞、页面打开慢等问题,打线程dump是最好的解决问题的途径。所谓线程dump也就是线程堆栈,获取到线程堆栈有两步:
(1)获取到线程的pid,可以通过使用jps命令,在Linux环境下还可以使用ps -ef | grep java
(2)打印线程堆栈,可以通过使用jstackpid命令,在Linux环境下还可以使用kill -3 pid
另外提一点,Thread类提供了一个getStackTrace()方法也可以用于获取线程堆栈。这是一个实例方法,因此此方法是和具体线程实例绑定的,每次获取获取到的是具体某个线程当前运行的堆栈。
53、怎么检测一个线程是否持有对象监视器?
解析:我也是在网上看到一道多线程面试题才知道有方法可以判断某个线程是否持有对象监视器:Thread类提供了一个holdsLock(Objectobj)方法,当且仅当对象obj的监视器被某条线程持有的时候才会返回true,注意这是一个static方法,这意味着"某条线程"指的是当前线程。
54、synchronized 和 ReentrantLock 的区别?
解析:synchronized是和if、else、for、while一样的关键字,ReentrantLock是类,这是二者的本质区别。既然ReentrantLock是类,那么它就提供了比synchronized更多更灵活的特性,可以被继承、可以有方法、可以有各种各样的类变量,ReentrantLock比synchronized的扩展性体现在几点上:
(1)ReentrantLock可以对获取锁的等待时间进行设置,这样就避免了死锁
(2)ReentrantLock可以获取各种锁的信息
(3)ReentrantLock可以灵活地实现多路通知
另外,二者的锁机制其实也是不一样的。ReentrantLock底层调用的是Unsafe的park方法加锁,
synchronized操作的应该是对象头中markword,这点我不能确定。
55、ConcurrentHashMap的并发度是什么?
解析:ConcurrentHashMap的并发度就是segment的大小,默认为16,这意味着最多同时可以有16条线程操作ConcurrentHashMap,这也是ConcurrentHashMap对Hashtable的最大优势。
56、ReentrantLock是什么?
解析:首先明确一下,不是说ReentrantLock不好,只是ReentrantLock某些时候有局限。如果使用ReentrantLock,可能本身是为了防止线程A在写数据、线程B在读数据造成的数据不一致,但这样,如果线程C在读数据、线程D也在读数据,读数据是不会改变数据的,没有必要加锁,但是还是加锁了,降低了程序的性能。
因为这个,才诞生了读写锁ReadWriteLock。ReadWriteLock是一个读写锁接口,ReentrantReadWriteLock是ReadWriteLock接口的一个具体实现,实现了读写的分离,读锁是共享的,写锁是独占的,读和读之间不会互斥,读和写、写和读、写和写之间才会互斥,提升了读写的性能。
57、FutureTask是什么?
解析:这个其实前面有提到过,FutureTask表示一个异步运算的任务。FutureTask里面可以传入一个Callable的具体实现类,可以对这个异步运算的任务的结果进行等待获取、判断是否已经完成、取消任务等操作。当然,由于FutureTask也是Runnable接口的实现类,所以FutureTask也可以放入线程池中。
58、Linux环境下如何查找哪个线程使用CPU最长?
解析:这是一个比较偏实践的问题,这种问题我觉得挺有意义的。可以这么做:
(1)获取项目的pid,jps或者ps -ef | grep java,这个前面有讲过
(2)top -H -p pid,顺序不能改变
这样就可以打印出当前的项目,每条线程占用CPU时间的百分比。注意这里打出的是LWP,也就是操作系统原生线程的线程号,我笔记本山没有部署Linux环境下的Java工程,因此没有办法截图演示,网友朋友们如果公司是使用Linux环境部署项目的话,可以尝试一下。
使用"top -H -p pid"+"jpspid"可以很容易地找到某条占用CPU高的线程的线程堆栈,从而定位占用CPU高的原因,一般是因为不当的代码操作导致了死循环。
最后提一点,"top -H -p pid"打出来的LWP是十进制的,"jps pid"打出来的本地线程号是十六进制的,转换一下,就能定位到占用CPU高的线程的当前线程堆栈了。
59、一个线程如果出现了运行时异常会怎么样?
解析:如果这个异常没有被捕获的话,这个线程就停止执行了。另外重要的一点是:如果这个线程持有某个某个对象的监视器,那么这个对象监视器会被立即释放。
60、如何在两个线程之间共享数据?
解析:通过在线程之间共享对象就可以了,然后通过wait/notify/notifyAll、await/signal/signalAll进行唤起和等待,比方说阻塞队列BlockingQueue就是为线程之间共享数据而设计的。
61、守护线程是什么?
解析:守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在Java中垃圾回收线程就是特殊的守护线程。
62、创建线程有哪几种方式?
解析:创建线程有三种方式:继承Thread重新run方法、实现Runnable接口、实现Callable接口。
63、说一下 runnable 和 callable 有什么区别?
解析:runnable 没有返回值,callable 可以拿到有返回值,callable 可以看作是 runnable 的补充。
64、线程有哪些状态?
解析:线程的状态
- NEW尚未启动
- RUNNABLE正在执行中
- BLOCKED阻塞的(被同步锁或者IO锁阻塞)
- WAITING永久等待状态
- TIMED_WAITING等待指定的时间重新被唤醒的状态
- TERMINATED执行完成
65、sleep() 和 wait() 有什么区别?
解析:类的不同:sleep()来自Thread,wait()来自Object。
释放锁:sleep()不释放锁;wait()释放锁。
用法不同:sleep()时间到会自动恢复;wait()可以使用notify()/notifyAll()直接唤醒。
66、notify() 和 notifyAll() 有什么区别?
解析:notifyAll()会唤醒所有的线程,notify()之后唤醒一个线程。notifyAll()调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify()只会唤醒一个线程,具体唤醒哪一个线程由虚拟机控制。
67、线程的 run() 和 start() 有什么区别?
解析:start()方法用于启动线程,run()方法用于执行线程的运行时代码。run()可以重复调用,而start()只能调用一次。
68、创建线程池有哪几种方式?
解析:线程池创建有七种方式,最核心的是最后一种。
newSingleThreadExecutor():它的特点在于工作线程数目被限制为1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过60秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用SynchronousQueue作为工作队列;
newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是无界的工作队列,任何时候最多有nThreads个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目nThreads;
newSingleThreadScheduledExecutor():创建单线程池,返回ScheduledExecutorService,可以进行定时或周期性的工作调度;
newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()类似,创建的是个ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程;
newWorkStealingPool(int parallelism):这是一个经常被人忽略的线程池,Java8才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;
ThreadPoolExecutor():是最原始的线程池创建,上面1-3创建方式都是对ThreadPoolExecutor的封装。
69、线程池都有哪些状态?
解析:RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
TIDYING:所有的任务都销毁了,workCount为0,线程池的状态在转换为TIDYING状态时,会执行钩子方法terminated()。
TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。
70、线程池中 submit() 和 execute() 方法有什么区别?
解析:execute():只能执行Runnable类型的任务。
submit():可以执行Runnable和Callable类型的任务。
Callable类型的任务可以获取执行的返回值,而Runnable执行无返回值。
71、在 Java 程序中怎么保证多线程的运行安全?
解析:
方法一:使用安全类,比如Java.util.concurrent下的类。
方法二:使用自动锁synchronized。
方法三:使用手动锁Lock。
手动锁Java示例代码如下:
Lock lock = new ReentrantLock();
lock. lock();
try {
System. out. println("获得锁");
} catch (Exception e) {
// TODO: handle exception
} finally {
System. out. println("释放锁"); lock. unlock();
}
72、多线程中 synchronized 锁升级的原理是什么?
解析:synchronized锁升级原理:在锁对象的对象头里面有一个threadid字段,在第一次访问的时候threadid为空,jvm让其持有偏向锁,并将threadid设置为其线程id,再次进入的时候会先判断threadid是否与其线程id一致。
如果一致则可以直接使用此对象,如果不一致,则升级偏向锁为轻量级锁,通过自旋循环一定次数来获取锁,执行一定次数之后,如果还没有正常获取到要使用的对象,此时就会把锁从轻量级升级为重量级锁,此过程就构成了synchronized锁的升级。
锁的升级的目的:锁升级是为了减低了锁带来的性能消耗。在Java6之后优化synchronized的实现方式,使用了偏向锁升级为轻量级锁再升级到重量级锁的方式,从而减低了锁带来的性能消耗。
73、什么是死锁?
解析:当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,就会发生AB两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。
74、怎么防止死锁?
解析:尽量使用tryLock(longtimeout,TimeUnitunit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
尽量使用Ja 以上是关于面经 - Java 中级进阶面试题的主要内容,如果未能解决你的问题,请参考以下文章 分享 2021 年最新阿里 java 面试题:java 初级 + 中级 + 高级面试题(附答案),让你的面试之路畅通无阻!