Java面试题

文章简介

在互联网高速发展的今天,高并发系统已成为企业级应用的核心能力。对于 Java 后端工程师,掌握高并发系统设计思路、优化策略以及常见面试题非常重要。本文整理了 高并发系统面试题及解析,涵盖线程模型、锁机制、缓存、消息队列、数据库优化、分布式架构等核心内容,每题附有简短答案和详细解析,帮助读者系统复习、深入理解高并发设计。

本文适合准备大厂 Java 后端岗位面试的开发者阅读,同时适合作为技术博客收藏与分享。更多高并发、系统架构实战面试题可参考:高并发系统面试题大全


目录

  1. 并发基础与线程模型(1-10)
  2. 锁机制与线程安全(11-20)
  3. 高并发缓存策略(21-25)
  4. 消息队列与异步处理(26-30)
  5. 数据库优化与分库分表(31-35)
  6. 分布式架构设计(36-40)
  7. 性能调优与监控(41-45)
  8. 实战问题解析(46-50)

面试题列表

并发基础与线程模型(1-10)

1. 什么是高并发系统?

  • 简短答案:能够在短时间内处理大量请求且保持稳定响应的系统。
  • 详细解析:高并发系统需要在请求高峰期仍能保证响应时间和吞吐量。关键设计点包括异步处理、缓存优化、负载均衡、服务拆分和资源隔离。

2. Java 中线程的生命周期有哪些?

  • 简短答案:新建、就绪、运行、阻塞、死亡。

  • 详细解析:线程状态变化如下:

    • 新建(New):创建 Thread 对象
    • 就绪(Runnable):等待 CPU 调度
    • 运行(Running):执行 run 方法
    • 阻塞(Blocked/Waiting/Timed Waiting):等待锁或资源
    • 死亡(Terminated):线程执行完毕

3. Java 如何创建线程?

  • 简短答案:继承 Thread 或实现 Runnable/Callable。
  • 详细解析
// 继承 Thread
class MyThread extends Thread {
    public void run() {
        System.out.println("Thread running");
    }
}
new MyThread().start();

// 实现 Runnable
class MyTask implements Runnable {
    public void run() {
        System.out.println("Runnable running");
    }
}
new Thread(new MyTask()).start();

// 使用 Callable + Future
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<Integer> future = executor.submit(() -> 1 + 2);

4. 什么是线程安全?

  • 简短答案:多线程访问共享资源时不产生数据不一致。
  • 详细解析:线程安全要求操作是原子性、可见性和有序性保证。常用方法包括使用 synchronized、ReentrantLock、原子类(AtomicInteger 等)和线程局部变量(ThreadLocal)。

5. Java 内存模型(JMM)主要关注什么?

  • 简短答案:可见性、有序性、原子性。

  • 详细解析:JMM 定义了线程如何访问和修改主内存和本地线程缓存。关键点:

    • 可见性:一个线程修改对其他线程可见(volatile)
    • 有序性:编译器和 CPU 不乱序执行重要操作
    • 原子性:操作不可被中断(synchronized、AtomicInteger)

6. synchronized 与 ReentrantLock 区别?

  • 简短答案:synchronized 是 JVM 内置,ReentrantLock 是 Java 类库,可响应中断和超时。

  • 详细解析

    • synchronized 自动释放锁,不能中断
    • ReentrantLock 可以中断等待、尝试加锁(tryLock)和公平锁
    • ReentrantLock 适合复杂锁逻辑

7. 线程池的核心参数有哪些?

  • 简短答案:核心线程数、最大线程数、队列容量、线程存活时间、拒绝策略。
  • 详细解析
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5,  // corePoolSize
    10, // maximumPoolSize
    60, // keepAliveTime
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100),
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

8. 线程池的好处?

  • 简短答案:减少线程创建开销,控制并发数量,提高资源利用率。
  • 详细解析:线程池复用线程、控制最大并发数、防止 OOM;配合队列可实现流量削峰和任务调度。

9. 什么是死锁?如何避免?

  • 简短答案:多个线程互相等待对方释放资源导致永久阻塞。

  • 详细解析:死锁条件:互斥、占有且等待、不可剥夺、循环等待。避免方法:

    • 避免嵌套锁
    • 使用 tryLock 或定时锁
    • 按固定顺序获取锁

10. Java 中 volatile 的作用?

  • 简短答案:保证变量可见性和禁止指令重排,不保证原子性。
  • 详细解析:volatile 修饰变量后,读写操作直接访问主内存,保证线程间可见性和有序性,但复合操作(i++)仍需加锁或使用原子类。

锁机制与线程安全(11-20)

11. ReentrantLock 的公平锁和非公平锁区别?

  • 简短答案:公平锁按申请顺序获取锁,非公平锁抢占锁更快。
  • 详细解析
ReentrantLock fairLock = new ReentrantLock(true); // 公平锁
ReentrantLock unfairLock = new ReentrantLock();   // 非公平锁

公平锁避免饥饿,但吞吐量低;非公平锁吞吐量高,但可能导致线程饥饿。

12. 什么是读写锁?

  • 简短答案:ReadWriteLock 提供读锁和写锁,允许多个读、单个写。
  • 详细解析:读写锁提高读多写少场景的性能。Java 实现:ReentrantReadWriteLock。

13. synchronized 的锁范围是?

  • 简短答案:对象或类级别。
  • 详细解析:方法锁定整个对象,静态方法锁定类,锁粒度影响并发性能。

14. 如何实现线程间通信?

  • 简短答案:wait()/notify()/notifyAll() 或 BlockingQueue。
  • 详细解析
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);
queue.put(1);  // 生产者
queue.take();  // 消费者

阻塞队列天然支持生产者-消费者模型,避免手动 wait/notify。

15. 什么是 CAS?

  • 简短答案:Compare-And-Swap,原子性操作。
  • 详细解析:CAS 比较内存值与预期值相等则更新,常用于原子类(AtomicInteger、AtomicReference),避免锁开销。

16. 高并发场景如何处理共享资源?

  • 简短答案:加锁、CAS、线程局部变量、无锁数据结构。
  • 详细解析:选择合适策略防止数据竞争,提高吞吐量。例如:计数器使用 AtomicInteger,无共享可用 ThreadLocal。

17. 线程安全集合有哪些?

  • 简短答案:ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue。
  • 详细解析:使用分段锁、写时复制或阻塞队列机制保证多线程安全访问,避免手动同步。

18. 如何避免锁竞争导致性能下降?

  • 简短答案:细化锁粒度、使用读写锁、减少临界区。
  • 详细解析:锁粒度越大并发越低,使用锁分离、CAS 等技术提升性能。

19. 高并发中如何实现线程池拒绝策略?

  • 简短答案:AbortPolicy、CallerRunsPolicy、DiscardPolicy、DiscardOldestPolicy。

  • 详细解析

    • AbortPolicy:抛出异常
    • CallerRunsPolicy:调用线程执行任务
    • DiscardPolicy:直接丢弃
    • DiscardOldestPolicy:丢弃最早任务

20. 线程饥饿和活锁如何处理?

  • 简短答案:公平锁、避免无限循环重试。
  • 详细解析:线程饥饿是低优先级线程长时间得不到执行;活锁是线程频繁重试导致无进展。通过公平锁和退避算法缓解。

高并发缓存策略(21-25)

21. 为什么使用缓存提升高并发系统性能?

  • 简短答案:减少数据库访问,降低延迟。
  • 详细解析:热点数据放入缓存(Redis、Memcached),大幅提高响应速度;结合本地缓存和分布式缓存优化吞吐量。

22. 缓存穿透、击穿和雪崩是什么?

  • 简短答案

    • 穿透:请求不存在数据,直接打到数据库
    • 击穿:热点 key 过期同时大量请求
    • 雪崩:大量缓存同时失效
  • 详细解析

    • 使用布隆过滤器防穿透
    • 热点缓存加互斥锁或逻辑过期防击穿
    • 缓存过期错峰和随机过期防雪崩

23. Redis 如何支持高并发?

  • 简短答案:单线程 + 内存操作 + 分片集群。
  • 详细解析:Redis 内存操作高效;Cluster 模式分片存储;结合 Lua 脚本保证原子性操作;使用哨兵或 Sentinel 高可用。

24. 本地缓存和分布式缓存区别?

  • 简短答案:本地缓存在 JVM 内存,分布式缓存跨多实例共享。
  • 详细解析:本地缓存访问快,但不共享;分布式缓存可同步多个应用实例,但增加网络开销。

25. 缓存一致性如何保证?

  • 简短答案:定时刷新、消息通知、读写穿透策略。

  • 详细解析:常用策略包括:

    • Cache Aside:先读缓存,缺失访问数据库并更新缓存
    • Write Through/Write Behind:写入同时更新缓存
    • 消息通知:数据库更新触发缓存更新

更多高并发缓存和微服务优化题可参考:高并发面试题库


消息队列与异步处理(26-30)

26. 消息队列在高并发系统中的作用?

  • 简短答案:解耦服务、削峰填谷、异步处理。
  • 详细解析:高并发场景下,通过 MQ 异步处理订单、通知或日志,降低数据库压力和系统阻塞。

27. 常用消息队列有哪些?

  • 简短答案:RabbitMQ、Kafka、RocketMQ、ActiveMQ。

  • 详细解析

    • RabbitMQ 适合可靠性高的场景
    • Kafka 高吞吐量,适合日志/事件流
    • RocketMQ 企业级消息队列,支持事务消息

28. 如何保证消息顺序?

  • 简短答案:同一队列或分区顺序消费。
  • 详细解析:Kafka 可通过 key 分区保证顺序;RabbitMQ 单队列消费顺序;跨分区顺序需要业务层处理。

29. 消息幂等如何保证?

  • 简短答案:唯一消息 ID 或去重机制。
  • 详细解析:消费前检查消息是否已处理,保证重复消费不会影响业务,如订单重复扣款问题。

30. 消息重试和死信队列如何实现?

  • 简短答案:失败重试,消费失败消息进入死信队列。
  • 详细解析:控制重试次数和间隔,避免无限循环;死信队列保存无法消费的消息供后续处理或人工干预。

数据库优化与分库分表(31-35)

31. 数据库优化常用手段?

  • 简短答案:索引优化、SQL 调优、分库分表、读写分离。
  • 详细解析:高并发场景下数据库瓶颈明显,需合理索引、拆分表和库,读写分离提高并发能力。

32. 什么是分库分表?

  • 简短答案:将数据拆分到多个库或表中,减轻单库压力。
  • 详细解析:水平拆分:同表不同数据;垂直拆分:不同业务表拆库;结合中间件(ShardingSphere)路由访问。

33. MySQL 如何处理高并发写入?

  • 简短答案:批量插入、分区表、异步写入、消息队列。
  • 详细解析:减少事务冲突和锁竞争,通过异步队列或分区策略缓解压力。

34. 乐观锁和悲观锁区别?

  • 简短答案:乐观锁假设冲突少,通过版本号控制;悲观锁假设冲突多,锁定数据。
  • 详细解析:乐观锁适合高并发读多写少场景;悲观锁保证严格一致性,但吞吐量低。

35. 如何避免数据库死锁?

  • 简短答案:固定加锁顺序、短事务、索引优化。
  • 详细解析:死锁通常发生在多事务交叉访问时,优化 SQL 语句、事务粒度和锁顺序可有效避免。

分布式架构设计(36-40)

36. 高并发系统为什么要做分布式?

  • 简短答案:单机资源有限,分布式可扩展和容错。
  • 详细解析:水平扩展服务器、分布式缓存、数据库分库分表、负载均衡,实现高吞吐量和高可用性。

37. 分布式锁如何实现?

  • 简短答案:Redis、ZooKeeper 或数据库实现。
  • 详细解析:保证多个实例对共享资源互斥访问,防止并发冲突。Redis 结合 SETNX 和过期时间可实现分布式锁。

38. 什么是服务限流?

  • 简短答案:控制接口请求速率,保护系统稳定。
  • 详细解析:常用策略:令牌桶、漏桶算法、滑动窗口;可结合网关或服务端实现。

39. 分布式系统如何保证数据一致性?

  • 简短答案:CAP 权衡、最终一致性、事务补偿。
  • 详细解析:强一致性和高可用难以兼顾,通常选择最终一致性策略,结合 Saga 或事件驱动保证数据正确。

40. 什么是幂等性设计?

  • 简短答案:多次请求结果相同。
  • 详细解析:接口多次调用不会重复业务操作,防止重复扣款或订单生成,常用唯一请求 ID 或状态校验实现。

更多分布式架构和高并发设计题可参考:系统架构面试题


性能调优与监控(41-45)

41. JVM 参数调优如何提升并发性能?

  • 简短答案:调整堆大小、GC 策略、线程栈大小。
  • 详细解析:合理堆分配防止频繁 GC;选择低延迟 GC(如 G1、ZGC)提升吞吐量;线程数和栈大小影响并发处理能力。

42. 如何监控高并发系统性能?

  • 简短答案:使用 Prometheus、Grafana、Actuator、日志分析。
  • 详细解析:收集指标(CPU、内存、请求延迟)、监控线程池状态、数据库连接池使用率、消息队列积压情况。

43. 什么是慢日志?

  • 简短答案:执行时间超过阈值的 SQL 或请求日志。
  • 详细解析:慢日志分析系统瓶颈,优化 SQL、接口或缓存,提高并发性能。

44. 系统如何实现压力测试?

  • 简短答案:JMeter、Gatling、Locust 等工具模拟高并发请求。
  • 详细解析:通过压测分析瓶颈,发现服务、数据库、缓存或消息队列的性能限制,指导优化。

更多Java面试题整理:

JVM面试题
MySQL面试题
Redis面试题
Spring面试题

完整面试题库:
https://myquotego.com/html/questions?_from=csdn_159020324_4

支持:
AI模拟面试
AI简历优化
2000+面试题

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐