博客记录-day174-面试

0 阅读7分钟

一、面试

1、为什么要用线程池?

✅什么是线程池,如何实现的?

线程池通过复用已创建的线程,避免了频繁创建和销毁线程的开销(如内存分配、JVM调度),从而提升系统性能。它能有效控制并发线程数量,防止资源耗尽,同时提供任务队列和拒绝策略,增强系统的稳定性和响应速度。此外,线程池简化了线程管理,支持定时、周期性任务执行,适用于高并发场景。

2、Java 里还有哪些使用了池化思想的技术?

Java 中池化技术的典型应用包括:

  • ​数据库连接池​​(如 HikariCP、Druid):复用数据库连接,减少连接创建开销。
  • ​对象池​​(如 Apache Commons Pool):缓存对象实例,避免重复初始化。
  • ​HTTP 连接池​​(如 Apache HttpClient):复用 HTTP 连接,提升请求效率。
  • ​线程池​​(如 ExecutorService):复用线程资源。
  • ​内存池​​(如 Netty 的 PooledByteBufAllocator):减少内存碎片和分配耗时。

3、Java 提供了哪几种线程池?

image.png

Java 通过 Executors 工厂类提供了四种线程池:

  1. ​FixedThreadPool​​:固定大小的线程池,使用无界队列,适用于负载稳定的场景。
  2. ​CachedThreadPool​​:可缓存的线程池,适合短时异步任务,线程数按需增长。
  3. ​ScheduledThreadPool​​:支持定时及周期性任务执行。
  4. ​SingleThreadExecutor​​:单线程顺序执行,保证任务无并发问题。
    此外,ForkJoinPool 用于分治任务(如递归分解任务),WorkStealingPool(JDK 8+)基于工作窃取算法提升并行效率。

4、它们的使用场景、区别及选择原则是什么?

  • ​FixedThreadPool​​:适合已知并发量且任务稳定的场景(如 Web 服务器请求处理)。
  • ​CachedThreadPool​​:适合执行大量短期异步任务(如批量数据处理),但需警惕无界队列导致 OOM。
  • ​ScheduledThreadPool​​:用于定时任务调度(如日志清理、心跳检测)。
  • ​SingleThreadExecutor​​:需保证顺序执行且无并发问题的场景(如事件回调)。
    选择原则:根据任务类型(CPU/IO密集)、并发量、资源限制及任务特性(是否需顺序执行)综合评估。

5、线程池的核心参数有哪些?

  • ​corePoolSize​​:核心线程数,即使空闲也保留。
  • ​maximumPoolSize​​:最大线程数,任务队列满时扩容的极限。
  • ​keepAliveTime​​:非核心线程的空闲存活时间。
  • ​workQueue​​:任务队列(如 LinkedBlockingQueueSynchronousQueue)。
  • ​threadFactory​​:线程创建工厂,可自定义线程名称、优先级等。
  • ​RejectedExecutionHandler​​:拒绝策略(如抛出异常、丢弃任务)。

6、如何根据 CPU 密集型和 IO 密集型任务设置参数?

  • ​CPU 密集型​​:核心线程数 = CPU 核心数 + 1(避免线程切换开销),队列长度适中。
  • ​IO 密集型​​:核心线程数 = CPU 核心数 × 2(因线程常阻塞等待 IO),队列可适当增大或使用有界队列。
    实际需结合系统负载测试调整,例如通过 Runtime.getRuntime().availableProcessors() 动态获取 CPU 核心数。

7、队列长度设置的依据是什么?

队列长度需权衡内存资源和任务处理效率:

  • ​有界队列​​(如 ArrayBlockingQueue):防止内存溢出,但需配置合理的拒绝策略。
  • ​无界队列​​(如 LinkedBlockingQueue):适合突发流量,但可能导致任务堆积。
    依据包括:系统可用内存、任务到达速率、任务处理时间、队列类型(如优先级队列需固定长度)。通常通过压力测试确定最佳值。

8、动态调整线程池组件时,超出部分的线程怎么办?

会调用锁,获得到锁后才会中断线程。

9、如何快速定位线程泄露问题?

  • ​线程转储分析​​:通过 jstack 或 VisualVM 生成线程快照,检查线程状态(如 BLOCKEDWAITING)及堆栈跟踪。
  • ​监控工具​​:使用 Prometheus + Grafana 监控线程数变化,或 Arthas 动态跟踪线程创建。
  • ​代码审查​​:检查线程池配置(如是否误用 Thread.sleep 或未释放资源)。
  • ​内存分析​​:MAT 工具分析 Thread 对象引用链,定位未回收的线程。

10、使用 Redis 实现动态调整的原因是什么?是否有替代方案?

Redis 支持原子操作和高性能读写,适合实时更新配置(如通过 SET 命令动态修改参数)。替代方案包括:

  • ​ZooKeeper/Etcd​​:通过监听机制实现配置同步。
  • ​数据库​​:存储配置表,定时轮询更新。
  • ​本地缓存​​:结合 Guava Cache 或 Caffeine,但需处理一致性。
    Redis 的临时节点(如结合 Sentinel)可用于故障转移,但更常见的动态调整是通过外部配置中心实现。

11、AQS 锁的实现原理是什么?

✅如何理解AQS?

AQS(AbstractQueuedSynchronizer)基于 CLH 队列的变体,使用一个 volatile int state 表示同步状态,线程通过 CAS 竞争修改状态。

  • ​独占模式​​(如 ReentrantLock):线程尝试获取锁,失败则进入等待队列,释放时唤醒队首。
  • ​共享模式​​(如 Semaphore):允许多个线程同时获取锁。
    AQS 内部维护双向链表(CLH 队列),通过 Node 对象管理等待线程,结合自旋和阻塞减少 CPU 消耗。

12、ThreadLocal 为什么用 ThreadLocalMap 而不是 HashMap

  • ​线程隔离​​:每个线程持有独立的 ThreadLocalMap,避免多线程竞争,无需同步开销。
  • ​内存泄漏预防​​:ThreadLocalMap 的 Entry 继承 WeakReference,当 ThreadLocal 实例被回收时,Entry 的键自动清除,防止内存泄漏(但值仍需手动清理)。
  • ​性能优化​​:直接访问线程内部的 Map,减少哈希冲突和锁竞争。

13、RunnableCallable接口的区别是什么?

  • ​返回值​​:Runnablerun() 无返回值,Callablecall() 返回泛型结果。
  • ​异常处理​​:Callable 允许抛出受检异常(checked exception),Runnable 的异常需在内部捕获。
  • ​用途​​:Runnable 用于简单异步任务,Callable 适用于需返回结果或抛出异常的场景(如 FutureTask)。

14、数据库分片有哪些方式?水平拆分的缺点是什么?

  • ​分片方式​​:

    • ​垂直分片​​:按业务拆分表(如订单库、用户库)。
    • ​水平分片​​:按规则(哈希、范围)拆分同一表的数据。
  • ​水平拆缺点​​:

    • 跨分片查询复杂(需聚合或冗余字段)。
    • 数据分布不均可能导致热点问题。
    • 扩容时需数据迁移,影响可用性。

15、SQL如何调优?

✅SQL执行计划分析的时候,要关注哪些信息?

image.png

image.png

image.png

16、数据库如何解决主从延迟问题?

✅什么是数据库的主从延迟,如何解决?

image.png

✅MySQL的并行复制原理

  • ​并行复制​​:从库多线程应用 relay log。
  • ​半同步复制​​:主库等待至少一个从库确认写入。
  • ​应用层优化​​:读写分离时,强一致性场景直接读主库,最终一致性场景异步读从库。
  • ​延迟监控​​:通过 SHOW SLAVE STATUS 监控 Seconds_Behind_Master,及时报警。

17、Redis 缓存穿透、雪崩、击穿的防御手段是什么?

✅什么是缓存击穿、缓存穿透、缓存雪崩?

  • ​穿透​​:布隆过滤器拦截非法请求,或缓存空值(设置较短 TTL)。
  • ​雪崩​​:随机过期时间,集群部署,永不过期+异步更新。
  • ​击穿​​:互斥锁(如 Redis 的 SETNX)或永不过期,后台线程定时刷新。

18、Redis 集群如何避免脑裂问题?选举临时节点的机制是什么?

  • ​脑裂预防​​:多数派原则(Quorum),配置 cluster-require-full-coverage no 避免部分节点宕机导致整体不可用。
  • ​临时节点​​:通过 ZooKeeper/Etcd 等协调服务创建临时节点,节点消失时自动触发选举。
  • ​选举机制​​:基于 Raft 或类似算法,节点通过心跳检测故障,多数派确认新主节点。

19、平时常用的设计模式有哪些?

  • ​单例模式​​(Spring Bean 默认作用域)。
  • ​工厂模式​​(JDBC 驱动、Hibernate SessionFactory)。
  • ​代理模式​​(AOP、动态代理)。
  • ​观察者模式​​(Spring 事件监听)。
  • ​策略模式​​(多支付渠道切换)。
  • ​装饰器模式​​(Java I/O 流)。
  • ​模板方法模式​​(Spring JdbcTemplate)。

20、Spring 框架中用到了哪些设计模式?

  • ​模板方法​​:JdbcTemplateRestTemplate 封装公共流程。
  • ​工厂模式​​:BeanFactory 创建 Bean 实例。
  • ​代理模式​​:JDK 动态代理或 CGLIB 实现 AOP。
  • ​单例模式​​:默认 Bean 作用域。
  • ​观察者模式​​:ApplicationEventApplicationListener
  • ​适配器模式​​:HandlerAdapter 适配不同处理器。
  • ​装饰器模式​​:BeanPostProcessor 增强 Bean 初始化过程。