楼主: Since123
190 0

[其他] 2025年金九银十Java 岗面试遇到的高频问题总结 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

40%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
20 点
帖子
1
精华
0
在线时间
0 小时
注册时间
2018-3-8
最后登录
2018-3-8

楼主
Since123 发表于 2025-12-5 14:34:18 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

面试是通往理想公司的关键一步,然而大多数人在求职过程中并不会一蹴而就。对于 Java 开发者来说,想要在众多候选人中脱颖而出,不仅需要扎实的技术能力,还需掌握一定的沟通技巧与应对策略,做到“知己知彼”,才能显著提升通过率。

通常情况下,企业招聘流程包含 3 到 4 轮面试,前几轮为技术面,最后一轮由 HR 主导。每轮面试时长约为 40 分钟。具体提问内容会根据应聘者的职级、现场表达的流畅度以及和面试官之间的互动氛围而定。若回答问题时常卡顿、表述不清或答案不准确,很可能几轮问题后即被终止;反之,若能引导对话节奏,形成良好的双向交流,则成功率将大幅提升。

考察内容主要分为两个维度:基础知识与实际应用。前者检验技术底子是否牢固,后者则关注项目经验、技术落地能力,或者面对特定场景能否提出合理的解决方案。

Java 核心知识点

  • 集合框架:如 ArrayList、HashMap 的底层实现原理。
  • 多线程机制:线程创建方式、锁机制、并发工具类等。
  • JVM 相关:内存模型、垃圾回收机制、类加载过程。

数据库相关问题

常涉及 MySQL 中索引的构建原理、事务的实现机制(如 MVCC)、大字段建索引的影响及优化策略等内容。

主流框架与中间件

  • Spring 框架:重点包括 IOC 和 AOP 的实现原理、常用注解的作用与使用场景。
  • 缓存组件:如 Redis 的数据结构、持久化机制、缓存穿透/击穿解决方案。
  • 消息队列:Kafka 或 RocketMQ 的基本架构、消息可靠性保障机制。

算法题考察

一般难度适中,重在测试逻辑思维和代码编写能力。建议在动手前仔细审题,确保理解需求后再开始编码,避免因误解而导致方向错误。

项目经验展示要点

介绍项目时应突出重点:自己承担的角色、负责的核心模块、解决的关键问题。避免提及不熟悉或未参与的部分,以防被深入追问导致被动。同时要注意观察面试官反应,避免堆砌专业术语造成沟通障碍。

这一环节旨在全面展现个人在真实项目中的实战能力,包括问题排查效率、响应速度、跨团队协作与表达能力等综合素质。

优秀的面试表现往往体现在能够主动引导话题走向。通过带有思考性的回答激发面试官兴趣,从而进入深度探讨模式。例如围绕一个技术点展开多轮问答,不仅能体现知识广度,也能展示技术深度。值得注意的是,面试官通常会从你的回答中提取关键词继续深挖,因此回答要有层次、有延展性,便于后续衔接。

常见项目类问题

  1. 请简要介绍一下你简历上的项目?你在其中主要负责哪些工作?
  2. 项目中遇到的最大挑战是什么?出现了哪些问题?你是如何解决的?从中获得了哪些经验?
  3. 能否画出该项目的整体架构图?
  4. 你认为当前项目有哪些可以优化的空间?(例如引入 Redis 缓存热点数据)
  5. 是否曾遇到过内存泄漏的情况?是如何定位并处理的?

项目实践中常见的技术难题包括:大数据量引发的内存溢出、程序性能瓶颈优化、算法效率对比验证、新观点支撑现有理论的方法论探索,以及如何高效地与导师或同事沟通推进任务进展。

操作系统与基础理论问题

  1. 进程与线程的区别是什么?
  2. 常见的进程调度算法有哪些?(重要)
  3. 常用的 IO 模型有哪些?
  4. select、poll 与 epoll 的区别?epoll 底层使用的数据结构是什么?
  5. 进程间通信的方式有哪些?线程间呢?
  6. fork 函数的功能是什么?
  7. 协程的基本概念?
  8. Linux 下进程与线程的关系?
  9. 如何通过进程 ID 查看其占用的端口?又如何通过端口号反查对应的进程 ID?
  10. 怎样查找系统中内存占用较高的进程?
  11. 僵尸进程是如何产生的?
  12. 孤儿进程的成因是什么?
  13. 什么是虚拟内存?它与物理内存之间有何关系?
  14. 分段与分页机制分别是什么?各自适用于什么场景?
  15. 用户态与内核态的区别?所有系统调用都会进入内核态吗?
  16. 日常使用频率较高的 Linux 命令有哪些?如何打开文件并搜索某个单词?如何在指定目录下查找包含 txt 的文件?
  17. 是否使用过 ping 命令?请简单说明其作用。TTL 的含义是什么?
  18. 如何判断一台主机是否开放了某个端口?
  19. 谈谈你最熟悉的几种设计模式(如工厂模式、观察者模式),并手写一个单例模式的实现。
  20. 哪些排序算法是稳定的?为什么直接插入排序属于稳定排序?各类排序算法的时间复杂度与空间复杂度分别是多少?
  21. 如何实现二叉树的非递归遍历?请简要描述思路。
  22. 硬链接与软链接的区别?
  23. 中断有哪些分类?
  24. 软中断与硬中断有何不同?
  25. 红黑树与平衡二叉树的区别?

Java 基础专项问题

  1. StringBuilder 与 StringBuffer 的区别?
  2. Java 如何实现连续内存空间的分配?

3.3 创建对象的方式有哪些?

在 Java 中,创建对象的常见方式包括:使用 new 关键字调用构造函数、通过反射机制(如 Class.newInstance() 或 Constructor.newInstance())、利用克隆机制(实现 Cloneable 接口并调用 clone() 方法),以及通过反序列化从字节流中恢复对象。这些方法适用于不同的场景,比如反射适合框架动态加载类,而克隆则用于快速复制已有实例。

3.4 抽象类与接口的区别

抽象类是不能被实例化的类,允许包含抽象方法和具体实现;接口在 JDK 8 之前只能定义抽象方法,但从 JDK 8 开始支持默认方法和静态方法。一个类只能继承一个抽象类,但可以实现多个接口。抽象类更适合表示“是什么”的关系,而接口强调“能做什么”的能力契约。

3.5 浅拷贝与深拷贝的区别

浅拷贝仅复制对象本身及其基本类型字段值,对于引用类型的成员变量,只复制其引用地址,导致原对象与副本共享同一块堆内存。深拷贝则会递归复制所有层级的数据,包括引用对象,使得原对象和副本完全独立。因此,修改深拷贝后的对象不会影响原始对象。

3.6 封装、继承、多态详解

封装是指将数据和操作数据的方法绑定在一起,并隐藏内部实现细节,仅暴露必要的访问接口,提升安全性和模块化程度。继承允许子类复用父类的属性和方法,实现代码重用。多态分为编译时多态和运行时多态:前者通过方法重载实现,在编译阶段确定调用版本;后者依赖于方法重写和动态绑定,在程序运行时根据实际对象类型决定执行哪个方法体。

3.7 泛型机制与类型擦除

泛型提供编译期类型检查,避免强制类型转换错误,增强集合等容器的安全性。Java 的泛型采用类型擦除实现,即在编译后泛型信息会被移除,替换为原始类型(如 Object)或限定类型。这意味着泛型仅存在于源码和编译阶段,运行时无法获取真实泛型参数类型。

3.8 静态代理的实现及局限性

静态代理需要为每一个目标类编写对应的代理类,实现相同的接口并在其中嵌入目标对象,从而控制对目标方法的访问。这种方式结构清晰,但当接口增多时会产生大量冗余代理类,维护成本高,扩展性差。

3.9 动态代理的作用与应用场景

动态代理可以在运行时动态生成代理类,无需提前编写具体代理实现。它广泛应用于 AOP(面向切面编程)中实现日志记录、事务管理等功能,也在 RPC 框架中用于远程调用的透明化处理。由于其实现灵活,常作为面试手写题考察候选人对反射和代理机制的理解。

3.10 JDK 动态代理与 CGLIB 的差异

JDK 动态代理基于接口生成代理对象,要求目标类实现至少一个接口;CGLIB 则通过继承方式生成子类来实现代理,适用于没有接口的类。JDK 代理使用 Proxy 和 InvocationHandler 实现,CGLIB 借助 ASM 字节码框架操作底层字节码。两者性能接近,但 CGLIB 更加灵活但也可能引发 final 方法无法代理的问题。

3.11 注解的理解及其解决的问题

注解是一种元数据形式,用来为代码添加额外信息而不改变其逻辑。它可以替代部分 XML 配置,简化开发流程,提高可读性。例如 Spring 使用 @Autowired 自动装配 Bean,JUnit 使用 @Test 标识测试方法。注解结合反射可在运行时解析并执行特定行为,提升了框架的自动化能力。

3.12 Java 反射机制及其缺点

反射允许程序在运行时获取类的信息并操作其属性、方法和构造器,打破了封装性限制。虽然功能强大,但也带来性能开销大、安全性降低、破坏封装等问题。然而,正是这种动态特性使框架能够实现依赖注入、对象映射、插件化架构等高级功能。

3.13 框架为何需要反射技术

框架通常需在未知具体类型的情况下进行对象创建和方法调用,反射提供了这种灵活性。例如 Spring 容器通过反射实例化 Bean 并注入依赖,MyBatis 利用反射设置查询结果到实体类字段。反射让框架具备通用性和扩展性,适应不同业务需求。

3.14 获取 Class 对象的两种常用方式

第一种是通过类名调用 .class 属性,如 String.class;第二种是通过对象调用 getClass() 方法。此外,还可以使用 Class.forName("全限定类名") 动态加载类并返回其 Class 对象,这在配置驱动或插件系统中非常常见。

3.15 内存溢出与内存泄露的典型场景

内存泄露场景:长时间持有无用对象引用(如静态集合未清理)、监听器未注销、内部类持有外部类引用过久、数据库连接未关闭等,都会导致垃圾回收器无法回收对象,造成内存占用持续增长。

内存溢出场景:创建超大数组超出堆空间限制、递归深度过大引发栈溢出、频繁创建临时对象导致 GC 压力剧增、加载大量资源文件未释放等,最终触发 OutOfMemoryError。

3.16 引用类型的分类:强、软、弱、虚引用

  • 强引用:最常见的引用形式,只要强引用存在,对象就不会被回收。
  • 软引用:在内存不足时才会被回收,适合缓存场景。
  • 弱引用:每次垃圾回收都会被清除,可用于构建 WeakHashMap。
  • 虚引用:最弱的一种引用,主要用于跟踪对象被回收的时机,无法通过虚引用获取对象实例。

3.17 虚引用的特点说明

虚引用的存在不影响对象的生命周期,也无法通过它获取所指向的对象。它的主要用途是配合引用队列(ReferenceQueue)监控对象是否已被垃圾收集器回收,常用于资源清理通知。

3.18 BIO、NIO 与 AIO 的区别

BIO(阻塞 I/O)模型中,每个连接对应一个线程,读写操作会阻塞当前线程直到完成。NIO(非阻塞 I/O)采用通道和缓冲区机制,支持单线程管理多个连接,通过选择器(Selector)实现事件驱动。AIO(异步 I/O)更进一步,读写操作由操作系统回调通知完成,真正实现异步非阻塞。NIO 适用于高并发网络服务,如 Netty 框架即基于此设计。

3.19 finalize() 方法的应用场景

finalize() 是 Object 类中的方法,可在对象被垃圾回收前由 JVM 调用一次,用于释放非内存资源(如文件句柄)。但由于调用时间不确定且性能较差,现已不推荐使用,建议显式调用 close() 方法或使用 try-with-resources 语句替代。

3.20 GC Root 对象的类型

GC Root 是垃圾回收算法中判断可达性的起点,主要包括:正在执行的方法中的局部变量、活跃线程、类的静态字段、JNI 引用等。只有从 GC Root 可达的对象才被认为是存活对象,其余不可达对象将被判定为可回收。

3.21 Class.forName 与 ClassLoader 的区别

Class.forName("类名") 不仅加载类还初始化该类(执行静态代码块),而 ClassLoader.loadClass() 仅加载类而不立即初始化。因此前者适用于需要主动触发类初始化的场景,如 JDBC 驱动注册;后者更适合延迟初始化以优化启动速度。

3.22 CopyOnWriteArrayList 与 CopyOnWriteArraySet 分析

CopyOnWrite 容器:这类容器在修改时复制整个底层数组,保证读操作无锁并发安全,适用于读多写少的场景,如事件监听列表。

缺点:每次写操作都要复制数组,开销较大;不适用于频繁更新的场景;可能导致数据一致性延迟,因为读取的是旧快照。

3.23 单例模式的重要性与实现

单例模式确保一个类只有一个实例,并提供全局访问点。常见的实现方式有饿汉式(类加载时创建)、懒汉式(首次使用时创建)、双重检查锁定、静态内部类和枚举方式。其中枚举法最为安全,防止反射攻击和序列化破坏。

3.24 Java 中右移运算符 >> 与无符号右移 >>> 的区别

>> 是有符号右移,高位补符号位(正数补0,负数补1);>>> 是无符号右移,无论正负,高位一律补0。例如 -1 >> 1 仍为 -1,而 -1 >>> 1 得到一个很大的正整数。

4.1 网络分层的意义

网络协议分层旨在将复杂的通信过程分解为多个层次,每一层负责特定功能,便于设计、实现和维护。各层之间通过接口协作,降低耦合度,提升系统的可扩展性和互操作性。

4.2 TCP/IP 四层模型概述

TCP/IP 模型分为四层:应用层(处理高层协议如 HTTP、FTP)、传输层(提供端到端通信,如 TCP、UDP)、网络层(负责寻址与路由,如 IP 协议)、链路层(管理物理传输,如以太网协议)。该模型是互联网通信的基础架构。

4.3 HTTP 所属层级与常见状态码

HTTP 是应用层协议,用于浏览器与服务器之间的数据交换。常见的状态码包括:200(成功)、301/302(重定向)、400(请求错误)、403(禁止访问)、404(未找到资源)、500(服务器内部错误)等,用于反馈请求处理结果。

4.4 HTTPS 与 HTTP 的主要区别

HTTPS 在 HTTP 基础上增加了 SSL/TLS 加密层,保障数据传输安全。它使用非对称加密协商密钥,再用对称加密传输数据,解决了 HTTP 明文传输易被窃听、篡改的风险,广泛用于支付、登录等敏感场景。

4.5 对称加密与非对称加密算法介绍

对称加密使用同一个密钥进行加密和解密(如 AES、DES),速度快但密钥分发困难;非对称加密使用公钥加密、私钥解密(如 RSA),安全性更高但计算复杂,常用于密钥交换和数字签名。

4.6 HTTP/2.0 特性解析

HTTP/2.0 支持多路复用,允许在单一连接上并行发送多个请求和响应,减少延迟;引入二进制帧格式代替文本协议;支持头部压缩(HPACK)和服务器推送,显著提升页面加载效率,尤其适合现代 Web 应用。

4.7 HTTP 报文结构与 TCP 关系

HTTP 请求报文包括请求行(方法、URL、协议版本)、请求头(附加信息如 Host、User-Agent)、空行和请求体(POST 数据等)。HTTP 建立在 TCP 之上,依赖其可靠传输服务,但自身是无状态协议,需借助 Cookie 或 Token 维持会话。

4.8 TCP 三次握手流程及原因

客户端发送 SYN 包进入 SYN_SENT 状态,服务端回应 SYN+ACK 进入 SYN_RCVD 状态,客户端再发 ACK 完成连接建立。三次握手确保双方都具备发送和接收能力,防止已失效的连接请求突然传入服务器造成资源浪费。

4.9 TCP 四次挥手过程及必要性

主动关闭方发送 FIN,对方回复 ACK;随后对方也发送 FIN,主动方回应 ACK。由于 TCP 是全双工通信,两端需独立关闭连接,因此需要四次交互才能彻底断开双向通道。

4.10 TCP 滑动窗口机制与可靠性保障

滑动窗口用于流量控制,动态调整发送速率以匹配接收方处理能力。TCP 的可靠性体现在确认应答、超时重传、数据校验、序号排序等方面。拥塞控制通过慢启动、拥塞避免、快重传、快恢复等算法调节发送窗口大小,防止网络过载。

4.11 UDP 与 TCP 的区别及适用场景

TCP 提供可靠、有序、基于连接的服务,适用于文件传输、网页浏览等;UDP 无连接、不可靠但速度快,适用于实时音视频、DNS 查询、广播通信等对延迟敏感的场景。

4.12 MAC 地址与 IP 地址的关系

MAC 地址是硬件地址,标识设备在网络中的物理位置;IP 地址是逻辑地址,用于跨网络寻址。尽管 MAC 地址唯一,但它不具备层次结构,无法支持大规模路由,故需 IP 地址实现全球互联。

4.13 访问电商网站的完整流程

用户输入网址后,首先进行 DNS 解析获取服务器 IP;然后建立 TCP 连接;接着发起 HTTPS 请求,经过 SSL 握手加密通信;服务器返回 HTML 页面及相关资源(CSS、JS、图片);浏览器渲染页面并保持会话(Cookie/Session)。过程中涉及 DNS、HTTP、HTTPS、TCP、IP 等多种协议协同工作。

4.14 电子邮件的发送流程

发件人通过 SMTP 协议将邮件提交给发送方邮件服务器;该服务器查找收件人域名的 MX 记录,并通过 SMTP 将邮件转发至接收方邮件服务器;收件人使用 POP3 或 IMAP 协议从服务器下载邮件。整个过程依赖 DNS 查询和多种邮件协议配合。

4.15 DNS 解析过程与劫持风险

DNS 解析从本地缓存开始,若未命中则依次查询本地 DNS 服务器、根域名服务器、顶级域服务器直至获得 IP 地址。DNS 劫持指攻击者篡改解析结果,将用户引导至恶意网站,可通过 DNSSEC 或 DoH 技术加以防范。

4.16 GET 与 POST 请求的本质差异

GET 请求参数附带在 URL 后,长度受限,可被缓存和收藏,安全性低;POST 参数位于请求体中,理论上无长度限制,不会被缓存,更适合传输敏感或大量数据。二者语义也不同:GET 用于获取资源,POST 用于提交数据。

4.17 Session 与 Cookie 的工作机制

Cookie 是存储在客户端的小段数据,由服务器通过 Set-Cookie 响应头下发;Session 是服务器端维护的状态信息,通常通过 Cookie 中的 JSESSIONID 来关联用户会话。Cookie 可设置有效期,Session 默认在会话结束后销毁。

4.18 如何在无状态 HTTP 上维持用户状态

HTTP 本身不保存状态,可通过 Cookie + Session 机制在服务器记录用户信息,或将状态信息编码至 Token(如 JWT)中交由客户端保存,后续请求携带 Token 实现身份识别,达到状态保持效果。

4.19 ARP 协议的功能

ARP(地址解析协议)用于将 IP 地址映射为对应的 MAC 地址。当主机需要向局域网内另一台设备发送数据时,先查本地 ARP 缓存,若无则广播 ARP 请求,目标机器回应自己的 MAC 地址,从而完成寻址。

4.20 DDos 攻击原理简述

DDoS(分布式拒绝服务)攻击通过控制大量僵尸主机向目标服务器发送海量请求,耗尽其带宽或资源,使其无法正常响应合法用户。常见类型包括 SYN Flood、HTTP Flood、UDP Flood 等,防御手段包括限流、CDN 分散流量、防火墙过滤等。

5.1 ArrayList 的扩容机制

ArrayList 初始容量为10,当元素数量超过当前容量时,会触发扩容操作。扩容策略为原容量的1.5倍(右移一位加自身),然后创建新数组并将旧数据复制过去。频繁扩容会影响性能,建议预先设置合理初始容量。

5.2 HashMap 底层实现与优化

HashMap 基于数组+链表+红黑树实现。JDK 1.8 引入红黑树是为了在哈希冲突严重时提升查找效率,当链表长度超过8且桶数组长度≥64时转化为红黑树。负载因子默认为0.75,平衡了空间利用率与冲突概率。

5.3 ConcurrentHashMap 实现原理

ConcurrentHashMap 在 JDK 1.8 中采用 Node 数组 + 链表/红黑树结构,通过 CAS + synchronized 控制并发写入,取代了早期的 Segment 分段锁机制。读操作不加锁,利用 volatile 保证可见性,提高了并发性能。

5.5 为什么 ConcurrentHashMap 的读操作不需要加锁

读操作依赖于 volatile 关键字修饰的节点值,保证了多线程环境下读取的最新性。同时其结构设计确保即使在写操作进行中,读线程也能安全遍历链表或树结构,从而实现无锁读取,极大提升了读密集场景下的吞吐量。

5.6 HashMap、LinkedHashMap、TreeMap 的对比

HashMap 不保证顺序,查找最快;LinkedHashMap 维护插入顺序或访问顺序,适合构建 LRU 缓存;TreeMap 基于红黑树实现,按键自然排序或自定义比较器排序,适用于有序遍历场景。

5.7 线程不安全的集合及其解决方案

ArrayList、HashMap、HashSet 等是非线程安全的,在多线程环境下可能引发数据错乱。可通过 Collections.synchronizedList/map 包装,或使用 CopyOnWriteArrayList、ConcurrentHashMap 等专为并发设计的集合类来解决。

5.8 快速失败(fail-fast)与安全失败(fail-safe)机制

fail-fast 机制在迭代过程中检测到集合被修改(除迭代器自身操作外),立即抛出 ConcurrentModificationException,如 ArrayList 的迭代器。fail-safe 则基于集合快照进行遍历,不会抛异常,如 CopyOnWriteArrayList 的迭代器,属于安全失败。

5.8 HashMap 多线程环境下的死循环问题

在 JDK 1.7 中,多线程同时进行 resize 操作可能导致链表形成环形结构,进而引起 get 操作无限循环。JDK 1.8 虽然改为尾插法缓解该问题,但仍建议在并发场景下使用 ConcurrentHashMap 替代。

6.1 多线程环境下保证线程安全的方法

可通过 synchronized 关键字实现同步代码块或方法,使用 ReentrantLock 显式加锁,利用 volatile 保证可见性,或借助原子类(如 AtomicInteger)进行无锁操作。此外,ThreadLocal 可实现线程隔离,避免共享变量竞争。

6.2 死锁示例代码描述

两个线程各自持有锁并等待对方释放另一把锁时会发生死锁。例如线程 A 持有锁1并尝试获取锁2,线程 B 持有锁2并尝试获取锁1,双方互相等待,程序陷入僵局。

6.3 volatile 关键字的作用

volatile 保证变量的内存可见性,即一个线程修改该变量后,其他线程能立即看到最新值。它禁止指令重排序,适用于状态标志位等简单场景,但不保证复合操作的原子性。

6.4 synchronized 的作用与底层原理

synchronized 实现同步控制,可修饰方法或代码块。底层依赖于 JVM 的监视器锁(Monitor),通过对象头中的 Mark Word 实现轻量级锁、重量级锁的升级过程,确保同一时刻只有一个线程能进入临界区。

6.5 ReentrantLock 与 synchronized 的区别

ReentrantLock 是 API 级别的锁,支持公平锁与非公平锁选择、可中断等待、超时获取锁等功能,灵活性更高;synchronized 是关键字级别,语法简洁,自动释放锁,但在 JDK 1.6 优化后性能差距已不大。

6.6 volatile 与 synchronized 的对比

volatile 仅保证可见性和禁止重排,不保证原子性;synchronized 既能保证可见性又能保证原子性,且可协调多个线程对临界资源的访问。volatile 适合单一变量的读写同步,synchronized 适用于复杂同步逻辑。

6.7 ReentrantLock 的实现机制

ReentrantLock 基于 AQS(AbstractQueuedSynchronizer)实现,内部维护一个 volatile state 变量表示锁状态,通过 CAS 更新 state,并利用双向队列管理等待线程。支持可重入,同一线程多次获取锁只需增加计数。

6.8 interrupt、interrupted 与 isInterrupted 的区别

interrupt() 用于中断线程,设置中断标志位;interrupted() 是静态方法,检测当前线程是否中断并清除标志位;isInterrupted() 是实例方法,仅检测标志位不清除。停止运行中线程可通过中断机制配合循环判断实现优雅退出。

6.9 线程池的核心要素与工作机制

线程池用于统一管理和复用线程资源,减少创建销毁开销。核心参数包括:核心线程数、最大线程数、空闲存活时间、阻塞队列、线程工厂、拒绝策略。工作流程为:提交任务优先使用核心线程,超出后进入队列,队列满则启用非核心线程,最后触发拒绝策略。

6.10 不同拒绝策略的应用场景

AbortPolicy 抛出异常,适用于关键任务不容错场景;CallerRunsPolicy 由调用者线程执行任务,减缓提交速度;DiscardPolicy 直接丢弃新任务;DiscardOldestPolicy 丢弃队列中最老任务,腾出空间。可根据业务容忍度选择合适策略。

6.11 线程死锁的解除方式

预防死锁可通过破坏四个必要条件之一:互斥、占有并等待、不可抢占、循环等待。检测与恢复手段包括超时放弃、定期检查资源图是否存在环、强制终止某个线程释放资源等。调试工具如 jstack 可帮助定位死锁线程。

6.12 ThreadLocal 的概念与原理

ThreadLocal 为每个线程提供独立的变量副本,实现线程间数据隔离。其内部通过 ThreadLocalMap 存储键值对,键为 ThreadLocal 实例,值为线程本地值。适用于数据库连接、用户上下文传递等场景。

6.13 为何 ThreadLocal 要用 private static 修饰

使用 private 限制外部访问,保证封装性;static 使 ThreadLocal 实例为类共享,避免重复创建,通常每个变量只需要一个 ThreadLocal 实例来管理所有线程的副本,符合单例管理原则。

6.14 ThreadLocal 存在哪些局限性?在线程池环境中使用 ThreadLocal 可能引发什么问题?

ThreadLocal 在使用过程中存在一些潜在缺陷。最典型的问题是内存泄漏:由于 ThreadLocal 的底层实现依赖于线程中的 ThreadLocalMap,而该 Map 的 Entry 继承自弱引用,如果线程长时间运行且不主动调用 remove() 方法,可能导致 Entry 的 key 虽被回收,但 value 依然存在于内存中,造成内存泄露。

当在线程池场景下使用 ThreadLocal 时,问题更加突出。因为线程池中的线程是复用的,一个线程可能先后执行多个任务。若前一个任务设置了 ThreadLocal 变量但未及时清理,后续任务可能会错误地读取到之前任务遗留的数据,导致数据污染或逻辑错误。因此,在使用完 ThreadLocal 后,务必调用其 remove() 方法释放资源。

6.15 Java 中常见的锁有哪些类型?

Java 提供了多种锁机制来支持并发编程,主要包括以下几种:

  • synchronized 关键字:JVM 层面提供的内置锁,可修饰方法或代码块,自动获取和释放锁,保证同一时刻只有一个线程可以执行同步代码。
  • ReentrantLock(可重入锁):java.util.concurrent 包下的显式锁,支持公平锁与非公平锁,提供了比 synchronized 更丰富的功能,如尝试获取锁、定时等待、中断响应等。
  • ReadWriteLock:读写锁接口,典型实现为 ReentrantReadWriteLock,允许多个读线程同时访问,但写线程独占,适用于读多写少的场景。
  • StampedLock:JDK 8 引入的高性能锁,支持三种模式:写锁、悲观读锁和乐观读,尤其在读操作频繁的情况下性能优于读写锁。
  • CAS 相关原子类:基于硬件指令实现的无锁机制,如 AtomicInteger 等,利用乐观锁思想通过 compare-and-swap 操作保证线程安全。

这些锁适用于不同的并发场景,开发者可根据实际需求选择合适的锁机制以提升程序性能与安全性。

6.16 请阐述乐观锁与悲观锁的概念及其应用场景。

悲观锁假设并发冲突很可能发生,因此在整个数据处理过程中都会持有锁,防止其他线程修改数据。典型的实现包括 synchronized 和 ReentrantLock。这类锁适合写操作较多、冲突概率高的场景,虽然安全性高,但可能带来较大的性能开销。

乐观锁则假设大多数情况下不会发生冲突,在操作数据时不加锁,而是在更新时检查在此期间是否有其他线程修改过数据(通常通过版本号或 CAS 机制实现)。如果发现冲突,则重试或抛出异常。乐观锁常见于数据库中的版本控制字段以及 Java 中的 Atomic 类型操作。

乐观锁适用于读多写少的场景,例如高并发系统中的计数器、库存扣减等,能够有效减少线程阻塞,提高吞吐量。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:金九银十 Java jav Modification Interrupted
相关内容:Java面试问题

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
扫码
拉您进交流群
GMT+8, 2026-2-16 16:30