某大厂跳动Java面试真题之问题与解答总结(二)

一、常见的GC回收器​编辑

在 Java 中,垃圾回收器(Garbage Collector, GC)负责自动管理内存,回收不再使用的对象。常见的 GC 回收器主要分为以下几种,每种回收器有不同的特点和适用场景。​编辑

1. Serial GC

  • 特点 :Serial GC 是最简单的垃圾回收器,它使用单线程进行垃圾回收。在年轻代的垃圾回收时,它会暂停应用线程的执行。Serial GC 适用于单核 CPU 或内存较小的环境。

  • 使用场景 :适用于小型应用程序,或者对暂停时间不敏感的场景。​编辑

  • 命令行参数-XX:+UseSerialGC

2. Parallel GC

  • 特点 :Parallel GC 通过多线程来执行垃圾回收,主要用于提高吞吐量。年轻代的回收会暂停应用程序的所有线程,因此在较高并发的环境中,可能会影响系统响应时间。

  • 使用场景 :适用于对响应时间不敏感、需要最大吞吐量的应用。

  • 命令行参数-XX:+UseParallelGC

3. Concurrent Mark-Sweep GC (CMS)

  • 特点 :CMS GC 通过并行的标记和清除步骤来减少垃圾回收的停顿时间。CMS GC 是为了减少垃圾回收时应用程序的停顿时间而设计的。它通过多线程并行进行标记和清理,同时在垃圾回收过程中,应用线程可以继续执行。

  • 使用场景 :适用于响应时间要求较高的应用,如 Web 服务器。

  • 命令行参数-XX:+UseConcMarkSweepGC

4. G1 GC (Garbage First GC)

  • 特点 :G1 GC 是为了高效处理大内存场景而设计的垃圾回收器。它将堆内存划分为多个区域,并进行分区域的回收,尽量控制每次垃圾回收的停顿时间。G1 GC 适用于对低停顿时间有严格要求的大型应用。

  • 使用场景 :适用于对延迟和停顿有严格要求的企业级应用,尤其是大内存应用。

  • 命令行参数-XX:+UseG1GC

5. ZGC (Z Garbage Collector)

  • 特点 :ZGC 是一种低延迟垃圾回收器,设计目标是尽量减少停顿时间。它支持大规模堆内存并且不受停顿时间的影响。

  • 使用场景 :适用于需要高吞吐量和低延迟的应用,特别是对内存要求极高的系统。

  • 命令行参数-XX:+UseZGC​编辑

6. Shenandoah GC

  • 特点 :Shenandoah GC 是另一个低延迟垃圾回收器,类似于 ZGC,专注于减少停顿时间。它通过并行和并发的方式进行标记、清理和回收,大大降低停顿时间。

  • 使用场景 :适用于延迟敏感型的应用,尤其是大规模数据处理。

  • 命令行参数-XX:+UseShenandoahGC


二、SpringMVC的请求过程

SpringMVC 是一个基于 Servlet 的请求-响应模型框架,它通过 DispatcherServlet 作为前端控制器来协调请求的处理。SpringMVC 请求过程如下:

  1. 客户端发起请求

    • 客户端(通常是浏览器)发送 HTTP 请求到服务器,通常是一个 GET 或 POST 请求。
  2. DispatcherServlet接收请求

    • 请求首先到达 DispatcherServlet,这是 SpringMVC 的核心,负责请求的分发和协调工作。
  3. HandlerMapping定位处理器

    • DispatcherServlet 使用 HandlerMapping 根据请求的 URL 找到相应的控制器方法。
  4. HandlerAdapter执行请求

    • HandlerAdapter 负责调用相应的控制器方法(即处理器)。
  5. Controller处理请求

    • 控制器方法处理请求,执行业务逻辑,并返回一个 ModelAndView 对象,包含了视图名称和数据模型。
  6. 视图解析

    • DispatcherServlet 通过 ViewResolver 根据返回的视图名称解析到实际的视图(如 JSP 页面)。
  7. 渲染视图

    • 视图渲染,将数据模型渲染到页面,并通过响应返回给客户端。

三、线程池(所有你知道的)

线程池是用于管理线程的工具类,它允许你重复使用已创建的线程,并在需要时创建新线程。线程池的使用能够提高应用程序的性能,避免频繁创建和销毁线程带来的开销。

1. 线程池的核心组成部分

  • Core Pool Size :线程池中保持的最小线程数。即使线程池中的线程没有任务需要执行,也会保持一定数量的线程。

  • Maximum Pool Size :线程池允许的最大线程数。如果提交的任务数超过核心线程数,则线程池会创建新的线程,直到达到最大线程数。

  • Keep Alive Time :线程池中空闲线程的存活时间,当线程池中的线程空闲时间超过这个阈值时,线程会被销毁。

  • Blocking Queue:当线程池中的线程数达到最大线程数时,任务会被放入阻塞队列,等待有线程空闲时再执行。

2. 常见的线程池实现

  • CachedThreadPool :适用于短时间内大量的任务提交,线程池的线程数可以根据需求动态调整,任务完成后,线程会被回收。

  • FixedThreadPool :适用于负载均衡的任务,线程数固定。当任务过多时,会被阻塞在队列中等待执行。

  • SingleThreadExecutor :只有一个线程,适合串行任务执行。

  • ScheduledThreadPool:用于定时任务的执行,支持定时或周期性任务的执行。

3. 线程池的原理

  • 线程池采用的是工作窃取算法(Work Stealing)来高效管理任务,减少线程创建和销毁的开销。当有新任务到来时,线程池首先尝试从阻塞队列中取出任务,若队列为空且当前线程池中的线程数少于最大线程数,则创建新的线程来执行任务。

  • 如果线程池中的线程数已经达到最大线程数,新任务则会被放入阻塞队列,等待空闲线程处理。


四、HashMap底层实现

HashMap 是基于哈希表的 Map 实现,它存储键值对数据。HashMap 的底层结构是数组 + 链表(或红黑树)。

  1. 数据结构
    • HashMap 底层使用一个数组 table 存储 Entry 对象,每个 Entry 存储一个键值对。Entry 对象由 key, value, next(指向链表下一个节点)组成。
  2. 哈希算法
    • 在 HashMap 中,键的哈希值决定了它在数组中的索引位置。HashMap 使用 hashCode() 方法和某种形式的扰动算法来计算存储位置。
  3. 冲突处理
    • 当多个键有相同的哈希值时,HashMap 会使用链表或红黑树来解决冲突。如果链表的长度超过一定阈值(8),会将链表转换为红黑树,以提高查询性能。
  4. 扩容机制
    • 当 HashMap 中的元素数量超过负载因子(默认是 0.75)与当前数组容量的乘积时,HashMap 会扩容(通常是原数组大小的两倍),并重新计算每个元素的位置。

五、ConcurrentHashMap

ConcurrentHashMap 是一个线程安全的哈希表,适用于并发场景下的高效读写。它通过分段锁的方式提高了并发性,避免了在多线程环境下的性能瓶颈。

  1. 分段锁
    • ConcurrentHashMap 将底层数据结构分为多个段(Segment),每个段都有一个独立的锁。这样,当多个线程访问不同段的数据时,它们可以并行操作,而不会相互阻塞。
  2. 扩容机制
    • 当当前 Segment 的负载因子超限时,ConcurrentHashMap 会扩容当前段,并使用 rehash 操作重新计算元素的位置。编辑

六、LinkedHashMap 底层数据结构及使用场景

1. LinkedHashMap 的底层数据结构

LinkedHashMapHashMap 的一个变种,它保留了元素的插入顺序(或访问顺序)。其底层结构由两部分组成:

  • 哈希表 :和 HashMap 一样,LinkedHashMap 也使用哈希表(数组 + 链表)来存储数据。每个键值对会根据其哈希值被分配到表的某个位置。
  • 双向链表LinkedHashMap 会为每个存储的元素维护一个双向链表。这个链表的节点包含每个元素的键值对,并且链表的节点按照元素的插入顺序或访问顺序排列。

2. 如何工作

  • LinkedHashMap 在每个元素的哈希表节点中,除了保存 keyvalue,还会维护两个额外的指针:

    • 前向指针before):指向前一个节点。

    • 后向指针after):指向后一个节点。

    通过这两个指针,LinkedHashMap 保证了元素按照插入顺序(或访问顺序)排列。

  • 插入顺序 :默认情况下,LinkedHashMap 按照元素插入的顺序来遍历它们,即迭代的顺序与元素被插入的顺序相同。

  • 访问顺序 :如果使用 accessOrdertrue,则 LinkedHashMap 会按照元素的访问顺序来排列。每次元素被访问时(通过 getput 操作),该元素会被移动到链表的尾部。

3. 使用场景

LinkedHashMap 的主要特点是保持顺序,它适用于以下几种场景:

  1. 需要按插入顺序遍历元素

    • 在一些场景下,我们需要按元素插入的顺序来遍历或处理数据,而不是按哈希值排序。此时 LinkedHashMapHashMap 更合适。

    • 例如:存储用户输入的历史记录、订单处理等。

  2. 实现缓存(LRU 缓存)

    • LinkedHashMap 可以通过配置 accessOrder = true 实现基于访问顺序的缓存机制。这种场景常见于实现 LRU(Least Recently Used)缓存。

    • 当缓存达到容量限制时,LinkedHashMap 会按照访问顺序删除最久未被访问的元素。

    • 例如:Web 缓存、文件缓存等。

  3. 需要频繁访问但不关心顺序

    • 在某些场景下,虽然顺序无关紧要,但仍需要比 HashMap 更高效的顺序遍历。LinkedHashMap 提供了比 HashMap 更有序的遍历方式。

    • 例如:记录和显示用户的最近访问记录、某些排序操作等。

4. 总结

  • LinkedHashMap 是一个结合了哈希表和双向链表的集合,它可以保留元素的插入顺序或访问顺序。
  • 它适用于那些对顺序有要求的场景,比如实现缓存、访问顺序控制等,或者需要按插入顺序遍历的场合。

相关推荐
绝无仅有3 小时前
某大厂跳动Java面试真题之问题与解答总结(三)
后端·面试·架构
草梅友仁3 小时前
草梅 Auth 1.10.0 完善人机验证功能 | 2025 年第 41 周草梅周报
开源·github·ai编程
大前端helloworld3 小时前
前端梳理体系从常问问题去完善-框架篇(Vue2&Vue3)
前端·javascript·面试
野犬寒鸦3 小时前
从零起步学习Redis || 第十章:主从复制的实现流程与常见问题处理方案深层解析
java·服务器·数据库·redis·后端·缓存
江上月5136 小时前
django与vue3的对接流程详解(上)
后端·python·django
秦禹辰6 小时前
轻量级开源文件共享系统PicoShare本地部署并实现公网环境文件共享
开发语言·后端·golang
Emrys_6 小时前
Redis 为什么这么快?一次彻底搞懂背-后的秘密 🚀
后端·面试
程序员小假6 小时前
我们来说一说 Java 自动装箱与拆箱是什么?
java·后端
随便写写6 小时前
python项目和环境管理工具 UV
后端