一、常见的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 请求过程如下:
-
客户端发起请求 :
- 客户端(通常是浏览器)发送 HTTP 请求到服务器,通常是一个 GET 或 POST 请求。
-
DispatcherServlet接收请求 :
- 请求首先到达
DispatcherServlet
,这是 SpringMVC 的核心,负责请求的分发和协调工作。
- 请求首先到达
-
HandlerMapping定位处理器 :
DispatcherServlet
使用HandlerMapping
根据请求的 URL 找到相应的控制器方法。
-
HandlerAdapter执行请求 :
HandlerAdapter
负责调用相应的控制器方法(即处理器)。
-
Controller处理请求 :
- 控制器方法处理请求,执行业务逻辑,并返回一个 ModelAndView 对象,包含了视图名称和数据模型。
-
视图解析 :
DispatcherServlet
通过ViewResolver
根据返回的视图名称解析到实际的视图(如 JSP 页面)。
-
渲染视图 :
- 视图渲染,将数据模型渲染到页面,并通过响应返回给客户端。
三、线程池(所有你知道的)
线程池是用于管理线程的工具类,它允许你重复使用已创建的线程,并在需要时创建新线程。线程池的使用能够提高应用程序的性能,避免频繁创建和销毁线程带来的开销。
1. 线程池的核心组成部分:
-
Core Pool Size :线程池中保持的最小线程数。即使线程池中的线程没有任务需要执行,也会保持一定数量的线程。
-
Maximum Pool Size :线程池允许的最大线程数。如果提交的任务数超过核心线程数,则线程池会创建新的线程,直到达到最大线程数。
-
Keep Alive Time :线程池中空闲线程的存活时间,当线程池中的线程空闲时间超过这个阈值时,线程会被销毁。
-
Blocking Queue:当线程池中的线程数达到最大线程数时,任务会被放入阻塞队列,等待有线程空闲时再执行。
2. 常见的线程池实现:
-
CachedThreadPool :适用于短时间内大量的任务提交,线程池的线程数可以根据需求动态调整,任务完成后,线程会被回收。
-
FixedThreadPool :适用于负载均衡的任务,线程数固定。当任务过多时,会被阻塞在队列中等待执行。
-
SingleThreadExecutor :只有一个线程,适合串行任务执行。
-
ScheduledThreadPool:用于定时任务的执行,支持定时或周期性任务的执行。
3. 线程池的原理:
-
线程池采用的是工作窃取算法(Work Stealing)来高效管理任务,减少线程创建和销毁的开销。当有新任务到来时,线程池首先尝试从阻塞队列中取出任务,若队列为空且当前线程池中的线程数少于最大线程数,则创建新的线程来执行任务。
-
如果线程池中的线程数已经达到最大线程数,新任务则会被放入阻塞队列,等待空闲线程处理。
四、HashMap底层实现
HashMap 是基于哈希表的 Map 实现,它存储键值对数据。HashMap 的底层结构是数组 + 链表(或红黑树)。
- 数据结构 :
- HashMap 底层使用一个数组
table
存储 Entry 对象,每个 Entry 存储一个键值对。Entry 对象由key
,value
,next
(指向链表下一个节点)组成。
- HashMap 底层使用一个数组
- 哈希算法 :
- 在 HashMap 中,键的哈希值决定了它在数组中的索引位置。HashMap 使用
hashCode()
方法和某种形式的扰动算法来计算存储位置。
- 在 HashMap 中,键的哈希值决定了它在数组中的索引位置。HashMap 使用
- 冲突处理 :
- 当多个键有相同的哈希值时,HashMap 会使用链表或红黑树来解决冲突。如果链表的长度超过一定阈值(8),会将链表转换为红黑树,以提高查询性能。
- 扩容机制 :
- 当 HashMap 中的元素数量超过负载因子(默认是 0.75)与当前数组容量的乘积时,HashMap 会扩容(通常是原数组大小的两倍),并重新计算每个元素的位置。
五、ConcurrentHashMap
ConcurrentHashMap 是一个线程安全的哈希表,适用于并发场景下的高效读写。它通过分段锁的方式提高了并发性,避免了在多线程环境下的性能瓶颈。
- 分段锁 :
- ConcurrentHashMap 将底层数据结构分为多个段(Segment),每个段都有一个独立的锁。这样,当多个线程访问不同段的数据时,它们可以并行操作,而不会相互阻塞。
- 扩容机制 :
- 当当前 Segment 的负载因子超限时,ConcurrentHashMap 会扩容当前段,并使用 rehash 操作重新计算元素的位置。
编辑
- 当当前 Segment 的负载因子超限时,ConcurrentHashMap 会扩容当前段,并使用 rehash 操作重新计算元素的位置。
六、LinkedHashMap 底层数据结构及使用场景
1. LinkedHashMap 的底层数据结构
LinkedHashMap
是 HashMap
的一个变种,它保留了元素的插入顺序(或访问顺序)。其底层结构由两部分组成:
- 哈希表 :和
HashMap
一样,LinkedHashMap
也使用哈希表(数组 + 链表)来存储数据。每个键值对会根据其哈希值被分配到表的某个位置。 - 双向链表 :
LinkedHashMap
会为每个存储的元素维护一个双向链表。这个链表的节点包含每个元素的键值对,并且链表的节点按照元素的插入顺序或访问顺序排列。
2. 如何工作
-
LinkedHashMap
在每个元素的哈希表节点中,除了保存key
和value
,还会维护两个额外的指针:-
前向指针 (
before
):指向前一个节点。 -
后向指针 (
after
):指向后一个节点。
通过这两个指针,
LinkedHashMap
保证了元素按照插入顺序(或访问顺序)排列。 -
-
插入顺序 :默认情况下,
LinkedHashMap
按照元素插入的顺序来遍历它们,即迭代的顺序与元素被插入的顺序相同。 -
访问顺序 :如果使用
accessOrder
为true
,则LinkedHashMap
会按照元素的访问顺序来排列。每次元素被访问时(通过get
或put
操作),该元素会被移动到链表的尾部。
3. 使用场景
LinkedHashMap
的主要特点是保持顺序,它适用于以下几种场景:
-
需要按插入顺序遍历元素 :
-
在一些场景下,我们需要按元素插入的顺序来遍历或处理数据,而不是按哈希值排序。此时
LinkedHashMap
比HashMap
更合适。 -
例如:存储用户输入的历史记录、订单处理等。
-
-
实现缓存(LRU 缓存) :
-
LinkedHashMap
可以通过配置accessOrder = true
实现基于访问顺序的缓存机制。这种场景常见于实现 LRU(Least Recently Used)缓存。 -
当缓存达到容量限制时,
LinkedHashMap
会按照访问顺序删除最久未被访问的元素。 -
例如:Web 缓存、文件缓存等。
-
-
需要频繁访问但不关心顺序 :
-
在某些场景下,虽然顺序无关紧要,但仍需要比
HashMap
更高效的顺序遍历。LinkedHashMap
提供了比HashMap
更有序的遍历方式。 -
例如:记录和显示用户的最近访问记录、某些排序操作等。
-
4. 总结
LinkedHashMap
是一个结合了哈希表和双向链表的集合,它可以保留元素的插入顺序或访问顺序。- 它适用于那些对顺序有要求的场景,比如实现缓存、访问顺序控制等,或者需要按插入顺序遍历的场合。