Java面试题(带答案)

一、Java 并发与集合

1. ConcurrentHashMap 特性

30 秒版:

  • JDK 1.7:分段锁(Segment),锁粒度比 Hashtable 小
  • JDK 1.8+:数组 + 链表/红黑树,用 CAS + synchronized 锁链表头节点
  • 支持高并发读写,读基本无锁(volatile + CAS)
  • 不允许 null key/value
  • size() 等统计用 LongAdder 思想,近似或分段统计
  • 扩容时多线程协助迁移

追问: 1.7 和 1.8 区别;为什么不用 Segment 了;和 HashMap 线程安全对比

2. HashMap 底层

30 秒版:

  • JDK 1.8:数组 + 链表 + 红黑树
  • 默认容量 16,负载因子 0.75,超过阈值扩容 2 倍
  • 链表长度 ≥ 8 且数组 ≥ 64 转红黑树;≤ 6 退化为链表
  • 通过 (n-1) & hash 定位桶
  • 非线程安全;1.7 头插可能死循环,1.8 尾插

3. 线程创建方式

方式 说明
继承 Thread 不推荐,单继承限制
实现 Runnable 推荐
实现 Callable + FutureTask 有返回值
线程池 ExecutorService 生产推荐
CompletableFuture 异步编排
ForkJoinPool 分治并行

4. Java 线程池

创建方式:

复制代码
// 推荐:显式 ThreadPoolExecutor
new ThreadPoolExecutor(
    corePoolSize,      // 核心线程数
    maximumPoolSize,   // 最大线程数
    keepAliveTime,     // 非核心线程空闲存活时间
    unit,
    workQueue,         // 任务队列
    threadFactory,
    rejectedHandler    // 拒绝策略
);

7 个参数含义:

  1. corePoolSize:常驻核心线程数
  2. maximumPoolSize:最大线程数
  3. keepAliveTime:非核心线程空闲多久销毁
  4. unit:时间单位
  5. workQueue:阻塞队列(ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、DelayQueue)
  6. threadFactory:线程命名、优先级
  7. rejectedHandler:队列满且线程满时策略(Abort、CallerRuns、Discard、DiscardOldest)

执行流程:

任务 → 核心线程未满?→ 创建核心线程

→ 队列未满?→ 入队

→ 线程数 < max?→ 创建非核心线程

→ 执行拒绝策略

生产建议: 不用 Executors.newFixedThreadPool(无界队列 OOM 风险)

5. synchronized 底层原理

  • 字节码:monitorenter / monitorexit
  • 锁对象关联 Monitor(管程),存在对象头 Mark Word
  • 锁升级:无锁 → 偏向锁 → 轻量级锁 → 重量级锁
  • 重量级锁依赖 OS Mutex,涉及用户态/内核态切换
  • wait/notify 依赖 Monitor

6. ReentrantLock vs synchronized

对比 synchronized ReentrantLock
层面 JVM 关键字 API(JUC)
释放锁 自动 必须 unlock()
可中断 lockInterruptibly()
公平锁 非公平 可选公平/非公平
条件变量 单个 wait/notify 多个 Condition
底层 Monitor AQS

相同: 可重入、互斥

二、JVM

7. JMM(Java 内存模型)

你说的"主副内存"就是:主内存 + 工作内存

线程1工作内存 ←→ 主内存 ←→ 线程2工作内存

  • 主内存:共享变量实际存储(堆)
  • 工作内存:线程私有缓存,存变量副本
  • 线程对变量操作在工作内存,写回主内存才可见

三大特性:

特性 含义
原子性 不可分割(synchronized、CAS)
可见性 修改对其他线程可见(volatile、synchronized)
有序性 禁止指令重排(volatile、happens-before)

happens-before 规则: 程序次序、锁、volatile、线程 start/join 等

8. 垃圾回收算法

算法 说明
标记-清除 标记存活对象,清除其余;有碎片
标记-复制 分两块,存活复制到另一块;适合新生代
标记-整理 存活对象向一端移动;适合老年代
分代收集 新生代复制,老年代标记整理/清除

如何判断死亡: 引用计数(Java 不用)、可达性分析(GC Roots)

9. 垃圾回收器(CMS、G1)

回收器 区域 特点
Serial 新生代 单线程
ParNew 新生代 多线程版 Serial
Parallel Scavenge 新生代 吞吐量优先
CMS 老年代 并发标记清除,低停顿;有碎片,已逐步淘汰
G1 全堆 分区(Region),可预测停顿,JDK 9+ 默认
ZGC / Shenandoah 全堆 超低延迟

CMS 流程: 初始标记(STW) → 并发标记 → 重新标记(STW) → 并发清除

缺点: 碎片、浮动垃圾、Concurrent Mode Failure 退化为 Full GC

G1 亮点: 按 Region 回收,优先回收垃圾多的区;Mixed GC

10. JVM 类加载机制

过程: 加载 → 验证 → 准备 → 解析 → 初始化

双亲委派:

自定义加载器 → 应用类加载器 → 扩展类加载器 → 启动类加载器(Bootstrap)

  • 先让父加载器加载,保证核心类不被篡改
  • 打破双亲委派:SPI(JDBC)、Tomcat、热部署

11. 深拷贝 vs 浅拷贝

浅拷贝 深拷贝
基本类型 复制值 复制值
引用类型 复制引用(共享对象) 递归复制新对象
实现 clone() 默认浅拷贝 序列化、手动递归、工具类

// 浅拷贝

Object clone = obj.clone();

// 深拷贝常用:序列化

ByteArrayOutputStream bos = new ByteArrayOutputStream();

ObjectOutputStream oos = new ObjectOutputStream(bos);

oos.writeObject(obj);

ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));

Object deep = ois.readObject();

12. 创建实例的方式

  1. new 关键字
  2. 反射 Class.newInstance() / Constructor.newInstance()
  3. clone()
  4. 反序列化
  5. 工厂方法 / 建造者模式
  6. Objenesis 等绕过构造器
  7. 前端 JSON 反序列化(Jackson/Fastjson)本质也是反射+构造

三、Java IO

13. Java IO 模型

模型 说明
BIO 阻塞 IO,一连接一线程
NIO 非阻塞 + Channel + Buffer + Selector,多路复用
AIO 异步 IO,回调(Linux 下 aio 支持有限)

NIO 核心: Selector.select() 监听多 Channel 事件,单线程处理多连接

Netty: 基于 NIO 的高性能网络框架,面试常一起说

四、Spring

14. IOC 理解

  • 控制反转:对象创建和依赖交给容器,不由 new
  • 依赖注入 DI:@Autowired@Resource 注入依赖
  • 流程:扫描 Bean → 解析 BeanDefinition → 实例化 → 属性注入 → 初始化 → 放入容器
  • 单例 Bean 默认缓存在一级缓存

15. AOP 理解

  • 横切关注点:日志、事务、权限
  • 基于 动态代理:有接口用 JDK 代理,无接口用 CGLIB
  • 核心:切点 Pointcut、通知 Advice、切面 Aspect

16. Spring 设计模式(至少 8 个)

模式 应用
单例 Bean 默认单例
工厂 BeanFactory、FactoryBean
代理 AOP JDK/CGLIB
模板方法 JdbcTemplate、RestTemplate
观察者 ApplicationEvent
适配器 HandlerAdapter
装饰器 BeanWrapper
策略 Resource 加载策略
责任链 Filter、Interceptor 链

手写单例(双重检查锁):

复制代码
public class Singleton {
    private static volatile Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

简单工厂:

复制代码
public class PayFactory {
    public static PayService create(String type) {
        return switch (type) {
            case "wx" -> new WxPayService();
            case "ali" -> new AliPayService();
            default -> throw new IllegalArgumentException();
        };
    }
}

17. Spring Boot 自动装配流程

  1. @SpringBootApplication = @Configuration + @EnableAutoConfiguration + @ComponentScan
  2. @EnableAutoConfiguration 导入 AutoConfigurationImportSelector
  3. 读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(2.7+)或 spring.factories(老版本)
  4. @ConditionalOnXxx 条件决定是否生效(如 OnClassOnProperty
  5. 自动配置类注册 Bean 到容器

例子: 引入 spring-boot-starter-data-redis 自动配 RedisTemplate

18. Spring Scope 作用域

Scope 说明
singleton 默认,容器内唯一
prototype 每次获取新建
request 每个 HTTP 请求一个
session 每个 Session 一个
application ServletContext 级别

19. Spring 循环依赖

仅单例 + 属性注入可解决(三级缓存):

一级 singletonObjects 成品 Bean

二级 earlySingletonObjects 早期暴露 Bean

三级 singletonFactories ObjectFactory(用于 AOP 代理)

流程:A 创建 → 放三级 → 注入 B → B 创建 → 从三级拿 A 早期引用 → B 完成 → A 完成

不能解决: 构造器循环依赖、prototype 循环依赖

20. Spring 事务(八股)

  • 基于 AOP 代理,@Transactional 在方法前后开启/提交/回滚
  • 传播行为: REQUIRED、REQUIRES_NEW、NESTED 等
  • 隔离级别: 默认 DB 默认,可指定
  • 回滚: 默认 RuntimeException;rollbackFor=Exception.class

失效场景:

  1. 非 public 方法
  2. 同类自调用(不走代理)
  3. 异常被 catch 吞掉
  4. 抛出 Checked Exception 默认不回滚
  5. Bean 未被 Spring 管理
  6. 数据库引擎不支持(MyISAM)

五、网络

21. TCP 三次握手

客户端 → SYN → 服务端

客户端 ← SYN+ACK ← 服务端

客户端 → ACK → 服务端

为什么三次: 确认双方收发能力,防止历史连接请求

22. TCP 四次挥手

客户端 → FIN → 服务端

客户端 ← ACK ← 服务端

客户端 ← FIN ← 服务端

客户端 → ACK → 服务端(等待 2MSL)

为什么四次: FIN 和 ACK 分开发;服务端可能还有数据要发

六、MySQL

23. InnoDB 数据结构 / B+ 树

  • InnoDB 索引用 B+ 树
  • 非叶子节点只存索引键 + 指针,不存数据
  • 叶子节点存完整数据(聚簇索引)或主键(二级索引)
  • 叶子节点双向链表,适合 范围查询
  • 树高低(通常 3~4 层存千万级),IO 少

对比 B 树: B+ 树叶子链表、非叶子不存数据,更适合磁盘页读取

24. MySQL 隔离级别

级别 脏读 不可重复读 幻读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ(InnoDB 默认) 基本解决*
SERIALIZABLE

*InnoDB RR 通过 MVCC + 间隙锁/next-key lock 很大程度避免幻读

MVCC: 隐藏列 trx_idroll_pointer,Read View 判断可见性

25. MyBatis 分页

方式 说明
LIMIT 手动 LIMIT offset, size
RowBounds 内存分页,假分页
PageHelper 拦截器自动改 SQL 加 LIMIT(最常用)
物理分页 推荐,数据库层 LIMIT
复制代码
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectAll();
PageInfo<User> page = new PageInfo<>(list);

七、Redis

26. Redis 基本数据结构

类型 底层实现 场景
String SDS 缓存、计数、分布式锁
Hash 哈希表/压缩列表 对象属性
List 双向链表/压缩列表/quicklist 队列、时间线
Set 哈希表/整数集合 去重、标签
ZSet 跳表 + 哈希表 排行榜
Bitmap String 扩展 签到、布隆
HyperLogLog 基数统计 UV
Stream 日志型 消息队列

27. Redis String 实现 vs Java String

Redis SDS Java String
结构 len + alloc + buf[] char[] / byte[](JDK 9+)
长度 O(1) 获取 O(n) 或已缓存
二进制 可存任意字节 文本为主
扩容 预分配,减少重分配 不可变,修改产生新对象
线程安全 单线程模型无需锁 不可变故线程安全

28. Redis 为什么快

  1. 纯内存操作
  2. 高效数据结构(SDS、跳表等)
  3. 单线程模型(6.0+ 多线程处理 IO),无锁竞争
  4. IO 多路复用(epoll)
  5. 简单协议 RESP,减少开销
  6. 合理 持久化策略(RDB/AOF 异步/子进程)

(你答的虚拟内存机制:Redis 4.0 后主要用内存,老版本 VM 已废弃,可提 内存淘汰策略 代替)

29. 分布式锁(SETNX + 看门狗)

基础:

SET lock_key unique_value NX EX 30

  • NX:不存在才设置
  • EX 30:过期防死锁
  • unique_value:防误删别人锁(Lua 脚本校验后 DEL)

看门狗(Redisson):

  • 获取锁后启动定时任务,每隔 lockWatchdogTimeout/3 续期
  • 业务未完成自动延长过期时间
  • 释放锁时取消续期

注意: 主从切换可能丢锁 → 红锁(争议大)或 Redisson + 足够 TTL + 业务幂等

30. 缓存穿透 / 雪崩

问题 原因 解决
穿透 查不存在的数据,绕过缓存打 DB 布隆过滤器、缓存空值(短 TTL)、参数校验
击穿 热点 key 过期瞬间大量请求打 DB 互斥锁、逻辑过期、热点永不过期
雪崩 大量 key 同时过期或 Redis 宕机 过期时间加随机、多级缓存、集群高可用、限流降级

31. Redis 与数据库同步

策略 说明
Cache Aside(常用) 读:先缓存后 DB;写:先更新 DB 再删缓存
延迟双删 删缓存 → 更新 DB → 延迟再删
先更新 DB 再删缓存 推荐,配合消息重试
Canal/CDC 监听 binlog 异步更新缓存
设置 TTL 最终一致兜底

原则: 强一致难,接受 最终一致;写操作以 DB 为准

八、消息队列

32. Kafka 集群模式 / 主从同步

Kafka 不用传统主从,靠 Partition + Replica:

Topic: order

Partition-0: Leader(Broker1) + Follower(Broker2, Broker3)

Partition-1: Leader(Broker2) + Follower(Broker1, Broker3)

  • Leader 处理读写,Follower 同步
  • ISR(In-Sync Replicas):与 Leader 差距在阈值内的副本
  • acks=0/1/all:生产者可靠性
  • HW/LEO:高水位,保证消费可见性

口述你做过主从同步:

Kafka 通过 Partition 副本 + ISR 机制保证高可用;acks=all 等 ISR 确认;min.insync.replicas 控制最少同步副本;Leader 挂了 Controller 从 ISR 选举新 Leader。

其他集群模式:

  • RabbitMQ:镜像队列、普通集群
  • RocketMQ:Master-Slave、DLedger 多副本

33. MQ 如何保证消息顺序消费

前提: 顺序只在 同一分区/队列 内保证

Kafka:

  • 同一业务 key hash(key) % partition 发到同一分区
  • 消费者单线程或 内存队列按 key 串行

RocketMQ:

  • MessageQueueSelector 选同一队列
  • 消费端加 分布式锁 或单线程消费该队列

注意: 重试、失败会乱序 → 业务层幂等 + 版本号

九、加密算法

类型 算法 用途
对称 AES、DES、3DES 大量数据加密
非对称 RSA、ECC 密钥交换、数字签名
摘要 MD5、SHA-256、SHA-512 完整性校验(MD5 不安全)
国密 SM2、SM3、SM4 国内合规

应用: HTTPS(RSA/ECDHE + AES)、密码存储(BCrypt/Argon2 加盐哈希,不用 MD5)

十、速查总表

题号 关键词
ConcurrentHashMap CAS + synchronized,1.8 无 Segment
IO 模型 BIO/NIO/AIO,Selector 多路复用
JMM 主内存/工作内存,可见性/有序性/原子性
CMS/G1 CMS 并发标记清除;G1 Region 分区
类加载 双亲委派,加载→验证→准备→解析→初始化
synchronized Monitor,锁升级
ReentrantLock AQS,可中断、公平、多 Condition
线程池 7 参数,核心→队列→最大→拒绝
Spring 事务 AOP,失效:自调用、非 public、吞异常
TCP 三次握手/四次挥手
B+ 树 叶子链表,范围查询,InnoDB 默认
隔离级别 RC/RR/MVCC/间隙锁
Kafka Partition + ISR + Leader 选举
分布式锁 SET NX EX + Lua + 看门狗
穿透/雪崩 布隆/空值/随机 TTL/集群
设计模式 单例、工厂、代理等 8+
循环依赖 三级缓存,仅单例属性注入
深/浅拷贝 clone 浅;序列化深
自动装配 @EnableAutoConfiguration + 条件注解
Redis 同步 Cache Aside,先更 DB 再删缓存