Java-面试题
发布时间:2026/9/30 10:51:06 作者:尧图编辑部 阅读量:1,286

Java面试题一、示例1.能介绍一下你做过的项目吗2.ConcurrentHashMap 是线程安全的吗为什么是安全的3.hashmap是如何解决hash冲突的4.使用过threadlocal吗使用过程中要注意些什么5.能详细说说为什么tcp连接是三次而不是四次6.事务的隔离级别有哪几种7.数据库的索引你了解吗什么是非聚簇索引和聚簇索引8.你了解aop和ioc吗aop你们在哪些场景使用了9.缓存你用过吗你在使用缓存的过程中有遇到过哪些问题你是怎么解决的呢?10.我看你简历上使用了spring cloud能聊聊为什么要用微服务架构吗11. 说说Spring的事务传播机制二、好题1、为什么要用 Redis 而不用 map做缓存?2、分布式系统和微服务的区别3、Autowired()和Resource的区别4、MyBatis 中比如 UserMapper.java 是接口为什么没有实现类还能调用5、super()关键字三、知识库TODO1.java集合对象引用jvmspringmybatisxxl-jobEasyExcel2.mysql性能优化3.redis4.linuxDevOps提示以下是本篇文章正文内容下面案例可供参考一、示例1.能介绍一下你做过的项目吗2.ConcurrentHashMap 是线程安全的吗为什么是安全的ConcurrentHashMap 是线程安全的。ConcurrentHashMap 通过使用分段锁或更细粒度的 CAS 操作、Node 节点、线程安全的扩容机制和优化的哈希函数等机制实现了线程安全性。这使得它能够在高并发环境下提供高效的并发性能。3.hashmap是如何解决hash冲突的HashMap 在 Java 中解决哈希冲突的方法主要采用了链地址法也称为拉链法。当两个或更多的键根据哈希函数计算出相同的哈希值即哈希冲突时HashMap 不会简单地用一个值替换另一个值而是将这些具有相同哈希值的键值对存储在一个链表中。总结来说HashMap 通过链地址法即拉链法和在某些情况下使用红黑树来解决哈希冲突从而实现了高效的键值对存储和查询。4.使用过threadlocal吗使用过程中要注意些什么ThreadLocal 是 Java 提供的一个类它提供了线程局部变量。这些变量与其他变量不同因为每一个访问这个变量的线程都有它自己的独立初始化的变量副本。在多线程环境中这可以用来存储线程特定的数据而不需要担心数据不一致或同步问题。在使用 ThreadLocal 的过程中需要注意以下几点内存泄漏ThreadLocal 的一个常见问题是内存泄漏。当 ThreadLocal 对象不再被引用并且当前线程试图访问它时由于 ThreadLocalMap 的键是弱引用WeakReference因此 ThreadLocal 对象会被垃圾回收。但是如果 ThreadLocalMap 的值即线程局部变量是强引用并且这些值很大或者数量很多那么它们可能不会被及时回收从而导致内存泄漏。为了避免这种情况应该在使用完 ThreadLocal 后调用 remove() 方法手动清理。线程池与 ThreadLocal当使用线程池时线程的生命周期可能很长这意味着 ThreadLocal 变量可能会在很长一段时间内都保持活动状态。因此在使用线程池时需要特别小心 ThreadLocal 的使用确保在不再需要时调用 remove() 方法。否则可能会出现内存泄漏或意外的数据保留。线程安全问题虽然 ThreadLocal 本身是线程安全的但它并不能保证线程中其他变量的线程安全性。因此在编写多线程代码时仍然需要注意其他变量的线程安全性问题。继承问题如果一个类继承了使用 ThreadLocal 的类并且重写了 ThreadLocal 的访问方法如 get() 或 set()那么可能会出现意外的行为。因此在设计和使用 ThreadLocal 时需要避免这种情况。清理资源在使用 ThreadLocal 存储资源如数据库连接、文件句柄等时需要确保在不再需要时及时清理这些资源避免资源泄漏。避免过度使用虽然 ThreadLocal 可以简化多线程编程中的某些问题但它并不适用于所有情况。过度使用 ThreadLocal 可能会导致代码变得难以理解和维护。因此在使用 ThreadLocal 之前应该仔细考虑是否真的需要它。避免静态 ThreadLocal尽量避免在静态字段中引用 ThreadLocal 实例因为这可能导致类加载器泄漏和内存泄漏。相反应该将 ThreadLocal 实例作为非静态字段创建并在需要时传递给其他方法或类。5.能详细说说为什么tcp连接是三次而不是四次简化连接过程三次握手已经足够完成连接建立所需的必要操作。通过三次握手客户端和服务器可以确认彼此的可达性和通信能力同时同步双方的初始序列号为后续的数据传输做好准备。四次握手虽然可以提供更多的确认步骤但在TCP连接建立的过程中并不是必需的。避免历史连接三次握手的一个重要目的是为了防止旧的重复连接初始化造成混乱。在网络中可能会出现客户端发送的连接请求因为网络问题而延迟到达服务器的情况。如果服务器只进行两次握手那么可能会错误地将过时的连接请求当作新的请求来处理从而建立了一个无效的连接。通过第三次握手客户端可以确认服务器的响应是针对自己最新的连接请求从而避免了历史连接的问题。提高效率使用三次握手可以在保证连接可靠性的同时提高连接建立的效率。在网络通信中每次通信都需要消耗一定的时间和资源。通过精简连接过程可以减少不必要的通信开销提高网络资源的利用率。6.事务的隔离级别有哪几种事务的隔离级别主要有四种它们是读未提交Read Uncommitted这是最低的隔离级别。一个事务可以读取另一个尚未提交的事务的数据。这种级别可能导致脏读、不可重复读和幻读。读已提交Read Committed一个事务只能读取已经提交事务所做的数据修改。这种级别可以防止脏读但可能出现不可重复读和幻读。它是大多数数据库系统的默认隔离级别例如SQL Server。可重复读Repeatable Read对同一字段的多次读取结果都是一致的。这是MySQL的默认事务隔离级别。它可以防止脏读和不可重复读但幻读仍有可能发生。可串行化Serializable最高的隔离级别。所有的事务依次逐个执行这样事务之间就不可能产生干扰。这种级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。因为所有的事务依次逐个执行这样事务之间就不可能产生干扰。7.数据库的索引你了解吗什么是非聚簇索引和聚簇索引数据库的索引是数据库中一种重要的数据结构其作用类似于图书的目录可以加快对表中数据的检索速度。每张表只能建一个聚簇索引当在InnoDB表中定义一个主键时该主键默认就会成为聚簇索引。聚簇索引和非聚簇索引的主要区别在于数据存储方式、唯一性和查询效率。聚簇索引将数据按照索引顺序存储在磁盘上查询效率高但唯一性强而非聚簇索引将索引和数据分开存储可以有多个且查询效率相对较低。在数据库设计和优化时需要根据实际需求选择合适的索引类型。8.你了解aop和ioc吗aop你们在哪些场景使用了AOP面向切面编程是一种程序设计范型。AOP的使用场景包括权限验证、事务管理、日志操作记录、异常处理、性能监控等。通过使用AOP可以将这些横切关注点与业务逻辑代码分离提高代码的模块化和可重用性。IoC控制反转是一种软件设计思想它将程序的控制权从程序内部转移到外部容器实现了程序的松耦合和可扩展性。IoC的原理是通过依赖注入和依赖查找来实现的。IoC的应用场景主要涉及以下几个方面管理对象依赖关系IoC容器可以自动注入对象之间的依赖关系避免手动创建对象并传递依赖减少代码的耦合度提高代码的可读性和可维护性。管理对象的生命周期IoC容器可以管理对象的生命周期当一个对象不再被使用时IoC容器可以自动销毁它释放资源避免内存泄漏等问题。管理配置信息IoC容器可以将配置信息和代码分离将配置信息集中管理降低代码和配置的耦合度便于维护和修改。9.缓存你用过吗你在使用缓存的过程中有遇到过哪些问题你是怎么解决的呢?缓存是一种存储数据的技术通过将经常访问的数据保存在临时存储器中以便将来需要时可以更快地获取。这样可以减少数据访问的时间和成本提高系统的性能和响应速度。在使用缓存的过程中我遇到过以下一些问题缓存穿透这是指查询一个数据库和缓存中都不存在的数据导致每次查询都会直接落到数据库上增加了数据库的负载。为了解决这个问题我采用了布隆过滤器等技术在查询前先判断查询的数据是否存在于缓存或数据库中如果不存在则不进行后续查询操作。缓存击穿当某个热点数据过期或者被删除时大量的请求同时进入数据库获取数据导致数据库压力过大。为了解决这个问题我添加了互斥锁或者使用分布式锁确保只有一个请求去数据库中查询数据其他请求则等待并使用缓存中的旧数据。缓存雪崩在缓存重启或者大量缓存集中在某一个时间段失效时大量的请求直接访问数据库导致数据库压力过大。为了应对这种情况我采用了多种缓存策略如设置缓存过期时间时加入随机值、设置缓存永不过期、利用Redis的持久化机制等。10.我看你简历上使用了spring cloud能聊聊为什么要用微服务架构吗使用Spring Cloud和微服务架构的原因有多方面以下是其中的一些关键点复杂性管理随着应用程序的增长和复杂性的增加传统的单体应用架构变得难以管理和维护。微服务架构通过将大型应用程序拆分为一系列小型、独立的服务使得每个服务都可以由不同的团队独立开发、测试、部署和扩展从而简化了复杂性管理。技术异构性微服务架构允许使用不同的技术栈和语言来构建服务这使得团队可以根据其专长和项目的需求选择最适合的技术。Spring Cloud作为微服务架构的框架提供了丰富的工具和库来支持各种技术栈如Java、Spring Boot等。可扩展性微服务架构的每个服务都可以独立扩展这意味着可以根据需要增加或减少特定服务的资源。这种灵活性使得系统能够更好地应对流量峰值和低谷同时保持较低的总体成本。容错性在微服务架构中如果某个服务出现故障其他服务仍然可以正常运行。此外通过使用Spring Cloud的断路器Hystrix等组件可以隔离故障服务防止其影响整个系统。快速迭代和交付由于微服务架构允许独立开发和部署服务因此可以更快地迭代和交付新功能。这使得团队能够更快地响应业务需求并保持竞争优势。服务重用微服务架构鼓励创建可重用的服务。通过将通用功能封装为服务可以在多个应用程序之间共享这些功能从而减少了重复工作并提高了开发效率。便于测试和部署由于微服务架构的每个服务都是独立的因此可以单独测试每个服务。此外使用容器技术如Docker和持续集成/持续部署CI/CD工具可以更容易地部署和更新服务。支持云原生应用微服务架构与云原生应用高度契合。通过将服务拆分为更小的单元可以更轻松地将其部署到云环境中并利用云的弹性、可扩展性和自动化特性。综上所述使用Spring Cloud和微服务架构可以帮助企业更好地管理复杂性、提高可扩展性和容错性、加速迭代和交付速度并支持云原生应用的发展。这些优势使得微服务架构成为当今许多大型企业和初创公司的首选架构。11. 说说Spring的事务传播机制简单来说当一个事务方法 A 调用另一个事务方法 B 时方法 B 的事务应该如何运行是加入方法 A 的现有事务还是开启一个新事务或者以非事务方式运行这就是事务传播机制要解决的问题。Spring 定义了七种事务传播行为其中 REQUIRED 是默认的传播行为表示如果当前存在事务则加入该事务如果当前没有事务则创建一个新的事务。二、好题1、为什么要用 Redis 而不用 map做缓存?内存管理Redis是专门设计用于内存存储的数据库它有着高效的内存管理机制。Redis会对存储的数据进行优化和压缩以提高内存利用率。而使用普通的Map做缓存需要手动管理内存容易导致内存泄漏或者内存溢出的问题。持久化支持Redis支持数据的持久化可以将内存中的数据保存到磁盘上以便在重启后恢复数据。而Map只是内存中的数据结构重启后数据会丢失。多种数据结构支持Redis不仅仅是一个简单的键值存储它支持多种数据结构如字符串、列表、哈希、集合和有序集合等。这使得Redis可以更灵活地处理不同类型的数据而Map只能存储简单的键值对。分布式支持Redis可以通过主从复制和集群模式实现数据的分布式存储和高可用性。而使用Map做缓存需要开发者自行实现分布式缓存机制增加了复杂性和开发成本。其他功能支持Redis还提供了其他功能如发布订阅、事务处理和Lua脚本执行等。这些功能使得Redis在缓存、消息队列和计数器等场景下有更广泛的应用。2、分布式系统和微服务的区别分布式系统和微服务是两个相关但不完全相同的概念。分布式系统Distributed System是指由多个独立的计算机节点通过网络连接组成的系统节点之间相互协作完成共同的任务。分布式系统关注整个系统的架构和通信模型旨在将一个大型的任务或问题分解为多个子任务在不同的计算机节点上进行并行处理。分布式系统可以采用各种技术和模型如消息传递、远程过程调用、分布式数据库等以实现节点之间的协作与数据交换。而微服务Microservices是一种软件架构风格将一个复杂的应用程序拆分成多个小型、自治的服务每个服务都独立运行、部署和扩展。微服务架构强调将应用程序划分为一组松耦合的服务每个服务都有自己的业务边界和数据存储方式并通过轻量级的通信机制如HTTP/REST进行交互。每个微服务都可以独立开发、测试、部署和维护从而提高了灵活性和可扩展性。因此可以说微服务是一种设计和组织分布式系统的方式它强调将系统划分为更小的、自治的服务单元以便更好地构建、扩展和维护。而分布式系统是一种更宏观的概念涵盖了多个计算机节点之间的通信和协作可以包含各种不同的架构和模型微服务只是其中一种实现方式。总结起来分布式系统是一个更广泛的概念指代由多个计算机节点组成的系统而微服务则是一种面向服务的软件架构风格用于设计和组织分布式系统中的服务单元。3、Autowired()和Resource的区别Autowired和Resource都是在 Spring 中用于依赖注入的注解它们有以下区别来源不同Autowired是 Spring 提供的注解而Resource是由 Java EE 提供的注解。因此Autowired只能在 Spring 应用中使用而Resource可以在任何 Java EE 应用中使用。注入方式不同Resource默认按照名称byName进行装配。如果没有找到与名称匹配的Bean则按照类型byType进行装配。如果按名称装配失败且按类型装配时有多个匹配的Bean则会抛出异常。当使用 Autowired 注解时Spring 会根据 Bean 的类型自动注入依赖。如果容器中存在多个相同类型的 BeanSpring 无法确定要注入哪个 Bean就会抛出异常。当类型匹配的Bean有多个时可以结合Qualifier注解来指定要注入的特定Bean。支持的注入对象不同Autowired可以注入任何 Spring 管理的 Bean包括自定义的 Bean、框架提供的 Bean 等。而Resource主要用于注入 Java EE 管理的资源如 EJB、JMS 连接工厂等。4、MyBatis 中比如 UserMapper.java 是接口为什么没有实现类还能调用在 MyBatis 中Mapper 接口例如 UserMapper.java没有具体的实现类但仍然可以被调用。这是因为 MyBatis 使用了动态代理来在运行时生成接口的实现类。在 MyBatis 的配置文件中我们会将 Mapper 接口与对应的 SQL 语句进行映射。当我们在代码中调用 Mapper 接口的方法时MyBatis 会通过动态代理机制生成一个代理对象该代理对象会拦截方法调用并根据配置文件中的映射关系执行相应的 SQL 语句。5、super()关键字在Java中继承是一种允许一个类称为子类或派生类继承另一个类称为父类或基类的属性和方法的机制。通过继承子类可以重用父类的字段和方法也可以定义自己的特有属性和方法。super() 是Java中用来调用父类构造器的关键字。在子类的构造器中如果没有显式调用父类的构造器Java编译器会自动插入对父类无参构造器的调用即super();。如果父类没有无参构造器或者子类构造器需要通过特定的参数初始化父类那么就需要显式地使用super(参数列表);来调用父类的带参构造器。三、知识库TODO1.java抽象、封装、继承、多态反射: 运行时获取类的属性和方法。AOP注解实现框架拓展Stringchar[]不是基础类型是线程安全的。集合Collection: List有序, Set无序唯一, QueueMap键值对数组链表初始容量16负载因子0.75线程安全的集合Vector只要是关键性的操作方法前面都加了synchronized关键字来保证线程的安全性Hashtable使用了synchronized关键字所以相较于Hashmap是线程安全的。ConcurrentHashMap:使用锁分段技术确保线性安全是一种高效但是线程安全的集合。Stack栈也是线程安全的继承于Vector。CopyOnWriteArrayList: 迭代器是弱一致性的, 是通过“写时复制”Copy-On-Write策略来保证写时线程安全的对象引用jvmjava虚拟机内存共享堆: 内存最大存储对象动态数组方法区: 元数据类信息常量静态变量私有虚拟机栈局部变量函数调用上下文本地方法栈用于调用操作系统的底层接口和硬件资源程序计数器记录当前线程所执行的字节码指令地址Java程序运行机制编写- 编译器编译 - 类加载器加载内存 - 执行引擎(解释器)运行垃圾回收机制(GC)四种引用类型强弱软虚springDI依赖注入AOP面向切面编程IOC控制反转容器松耦合MVCModel-View-Controller框架数据访问ORM事务管理mybatisMyBatis 是一个基于 Java 的持久层框架其运行原理可分为以下核心步骤配置加载阶段解析配置文件加载 mybatis-config.xml数据源、事务管理器、全局设置等。映射文件解析读取 Mapper.xml 文件SQL 语句、参数映射、结果集映射规则。生成 SqlSessionFactory通过 SqlSessionFactoryBuilder 构建全局唯一的工厂对象SQL 执行阶段(1) 创建 SqlSession通过 SqlSessionFactory.openSession() 创建会话封装了数据库连接和事务。(2) 获取 Mapper 代理对象MyBatis 通过 动态代理 为 Mapper 接口生成实现类。代理逻辑拦截接口方法关联到映射文件中的 SQL 语句。(3) SQL 执行流程参数处理将 Java 对象转换为 SQL 参数通过 ParameterHandler。SQL 解析将 #{} 或 ${} 替换为实际参数值。执行 SQL由 Executor 执行包含 Simple、Reuse、Batch 三种类型。可能触发一级缓存SqlSession 级别。结果映射通过 ResultSetHandler 将 ResultSet 转换为 Java 对象事务与资源释放扩展机制插件Plugin通过拦截器修改核心组件行为如分页插件。二级缓存跨 SqlSession 的缓存需在映射文件中配置 。mybatis一级缓存(本地): 默认开启sqlsession二级缓存(全局): 默认关闭命名空间MyBatis 的核心优势是 SQL 与代码解耦 灵活的映射通过动态代理和组件协作简化数据库操作。xxl-job分布式任务调度平台EasyExcel流式处理2.mysql开源的关系型数据库管理系统引擎: 默认InnoDB,支持事务索引: 一种数据结构聚簇索引唯一非聚簇索引多个事务: 读未提交读已提交可重复读(mysql默认)串行化ACID原子性一致性隔离性持久性spring事务的传播行为默认REQUIRED锁: 共享锁读锁排他锁写锁避免死锁性能优化分析负载慢SQL日志优化数据库语句SQL优化数据库结构表结构调整硬件资源扩容3.redis开源的非关系型数据库String, List(有序), Set(不可重复), Zset(分数排序), Hash(键值对)单线程事件驱动机制支持事务不支持回滚持久化机制RDB(二进制),AOF(追加写)缓存雪崩(同时失效)缓存击穿(热点失效)缓存穿透(恶意请求)缓存分布式锁消息队列计数器4.linuxCPU过高的分析步骤1.执行“top”命令查看所有进程占系统CPU的排序。2.执行“top -Hp 进程号”命令查看java进程下的所有线程占CPU的情况。3.执行“printf %x\n 10命令 后续查看线程堆栈信息展示的都是十六进制为了找到咱们的线程堆栈信息咱们需要把线程号转成16进制。4.执行 “jstack 进程号 | grep 线程ID” 查找某进程下线程IDjstack堆栈信息中的nid0xa的线程状态。如果““VM Thread” os_prio0 tid0x00007f871806e000 nid0xa runnable”第一个双引号圈起来的就是线程名如果是“VM Thread”这就是虚拟机GC回收线程了排查思路DevOps