Skip to main content

综合81-100

81.为什么 TCP 挥手需要有 TIME_WAIT 状态?

展开
  • 可靠性:TIME_WAIT 出现在主动关闭方,等待 2×MSL 的目的是若对端最后一个 FIN 的确认 ACK 丢失,可以在对端重传 FIN 时再次发送 ACK,确保四次挥手可靠结束。
  • 安全性(避免旧报文干扰):等待 2×MSL 能让网络中属于该连接四元组的“旧的/重复”分段全部过期,避免同一四元组被新连接复用时收到幽灵数据导致数据错乱。
  • 对象:只有主动关闭连接的一侧进入 TIME_WAIT。
  • 时长:2×MSL(实现通常设置为 1~4 分钟)。TIME_WAIT 激增会消耗端口/内核资源,可通过长连接/连接复用、增大临时端口范围、合理服务端并发设计等缓解(不应简单绕过该语义)。

82.Spring Boot 的核心特性有哪些?

展开 中等 VIP Spring Boot 后端
  • 自动配置(AutoConfiguration):基于类路径与条件注解按需装配常用组件,减少样板配置。
  • Starters:按功能划分的起步依赖,开箱即用(如 spring-boot-starter-webdata-redis)。
  • 嵌入式容器:内置 Tomcat/Jetty/Undertow,Jar 即可运行,便于部署与容器化。
  • 外部化配置:统一的 application.yml/properties@ConfigurationPropertiesProfile 多环境支持。
  • 约定优于配置:合理默认值提升开发效率,可逐步显式化配置。
  • 开发者体验:Spring Initializr 脚手架,良好测试支持(@SpringBootTest)。

83.为什么 HashMap 在 Java 中扩容时采用 2 的 n 次方倍?

展开 中等 Java 集合 Java
  • 高效寻址,算索引下标的时候用与位运算:容量为 2 的幂,索引可用 (n - 1) & hash,避免昂贵的取模运算,与位运算配合能更好地利用哈希高位,降低冲突概率(JDK 8 混淆高位至低位)。

  • 高效再分布:扩容到 newCap = oldCap << 1 时,节点要么保持原索引,要么移动到 oldIndex + oldCap,无需重新计算完整哈希,迁移成本低。

  • 决策规则:看新增位(hash & oldCap)。等于 0 → 保持 oldIndex;不等于 0 → 移动到 oldIndex + oldCap

  • 公式:oldIndex = hash & (oldCap - 1)newIndex = ((hash & oldCap) == 0) ? oldIndex : oldIndex + oldCap

int oldIndex = hash & (oldCap - 1);
int newIndex = (hash & oldCap) == 0 ? oldIndex : oldIndex + oldCap;

84.你在项目中使用的 Redis 客户端是什么?

展开 简单 VIP 后端 Redis
  • 我们项目里用默认的Lettuce,加上Redisson做分布式锁

  • Java 生态常见选择:

    • Lettuce:Netty 驱动,基于异步/响应式,线程安全,Spring Data Redis 默认推荐。
    • Jedis:历史较久,直观易用;早期连接非线程安全,需使用连接池。
    • Redisson:提供分布式对象与高级特性(锁、限流、队列、延时队列、执行器等)。
  • 选型建议:

    • 常规 KV/缓存:优先 Lettuce(性能/线程模型优)。
    • 需要高级分布式原语:考虑 Redisson。

85.TCP 超时重传机制是为了解决什么问题?

展开 简单 VIP 网络
  • 目的:确保TCP的可靠性
  • 发送方每发送一个报文段,都会启动一个计时器,然后等待ACK,如果计时器超时,则重传报文段
  • 过程
    • 发送数据并启动计时器:发送方每发送一个包含数据的TCP报文段,都会为其启动一个独立的重传计时器。
    • 等待确认:发送方等待接收方返回对该报文段的确认(ACK)。
    • 超时处理:
      • 成功接收ACK:如果在计时器超时之前收到了有效的ACK,则取消该计时器,数据传输成功。
      • 计时器超时:如果在规定时间内未能收到ACK,则认为数据包丢失。发送方会重新发送该数据包,并重新设置一个更长的超时时间(通常是上一次的两倍,即“指数退避”策略),然后再次等待确认。
    • 多次重传失败:如果多次重传仍然失败,发送方会认为网络连接存在严重问题,最终可能会放弃连接。

86.简述 MyBatis 的插件运行原理,以及如何编写一个插件?

展开 中等 VIP 后端 MyBatis
  • 原理

基于动态代理与责任链模式,对核心组件方法进行拦截。

  • 编写步骤

    • 实现 org.apache.ibatis.plugin.Interceptor 接口,重写三个方法:
      • Object intercept(Invocation invocation):核心拦截逻辑,这里编写自定义行为。
      • Object plugin(Object target):决定是否包装目标对象,通常使用 Plugin.wrap(target, this) 创建代理。
      • void setProperties(Properties properties):可选,用于接收插件配置参数。
    • 使用注解指定拦截点:
      • @Intercepts:标注类,包含一个或多个 @Signature
      • @Signature:指定拦截的类型(type)、方法(method)和参数类型(args)。
        • type:
          • Executor(执行器,负责整体 SQL 执行)。
          • ParameterHandler(参数处理器,处理 SQL 参数)。
          • ResultSetHandler(结果集处理器,处理查询结果)。
          • StatementHandler(语句处理器,处理 JDBC Statement)。
    • 配置插件:
      • 在 mybatis-config.xml 中添加 标签,指定插件类和可选属性。
      • 或者在spring config配置
  • 四个核心接口及其方法的执行顺序

    • 典型查询调用栈(简化):

      1. Executor.query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler)
        • 作用:
          • 先查本地缓存/二级缓存(若开启)。
          • 未命中时创建 CacheKey 与 BoundSql,委托 BaseExecutor.queryFromDatabase → doQuery。
        • 参数:
          • ms:映射的语句与配置(SQL、参数映射、返回映射等)。
          • parameter:入参对象(可为 Map/POJO/基础类型)。
          • rowBounds:逻辑分页(offset/limit)。
          • resultHandler:自定义结果处理器(可选)。
      2. StatementHandler.prepare(Connection, Integer timeout) → parameterize(Statement)
        • 创建并配置 JDBC Statement/PreparedStatement,绑定 SQL。
      3. StatementHandler.query(Statement, ResultHandler)
        • 内部委托 ParameterHandler.setParameters(PreparedStatement) 设置占位符参数,执行 JDBC 查询。
      4. ResultSetHandler.handleResultSets(Statement)
        • 将 ResultSet 映射为目标对象集合(映射列到属性、嵌套映射、延迟加载等)。
      5. Executor 写入本地/二级缓存(若可缓存),返回结果集合。
    • 核心接口职责速览:

      • Executor:增删改 update(...),查询 query(...)commit/rollbackcreateCacheKeyclearLocalCache,装饰实现如 CachingExecutor 负责缓存拦截。
      • StatementHandler:prepare/parameterize/batch/update/query,封装 JDBC Statement 的创建、参数化与执行。
      • ParameterHandler:getParameterObject/setParameters,负责将实参按映射设入 PreparedStatement。
      • ResultSetHandler:handleResultSets/handleOutputParameters,负责将结果集映射为对象或集合。
  • 案例

    • 记录SQL的执行耗时
      • 拦截点:StatementHandler的prepare方法
    • 避免误操作导致的UPDATE/DELETE 全表
      • 拦截点:Executor的update方法,判断sql的类型
  • 示例:

@Intercepts({
@Signature(type = Executor.class, method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "update",
args = {MappedStatement.class, Object.class})
})
public class MetricInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
long start = System.nanoTime();
try { return invocation.proceed(); }
finally { long costMicros = (System.nanoTime() - start) / 1000; /* 记录耗时 */ }
}
@Override
public Object plugin(Object target) { return Plugin.wrap(target, this); }
@Override
public void setProperties(Properties properties) { }
}

87.数组和链表在 Java 中的区别是什么?

展开 中等 Java 集合 Java
  • 存储结构:数组连续内存,链表离散节点(额外指针/对象头开销)。
  • 访问性能:数组随机访问 O(1);链表需要遍历 O(n)。
  • 插入/删除:
    • 数组中间插入/删除需搬移 O(n);
    • 链表结点插入/删除 O(1)(已得前驱),否则是O(n)。
  • 修改元素
    • 数组:通过索引直接修改,时间复杂度为 O(1)。
    • 链表:需要遍历到目标节点,时间复杂度为 O(n)。
  • 大小调整:数组成本高,链表更加灵活
  • 典型实现:ArrayList 基于数组,LinkedList 为双向链表。
  • 使用建议:读多随机访问选数组;频繁中间插入/删除且能定位前驱选链表。

88.Redis 中常见的数据类型有哪些?

展开 简单 VIP 后端 Redis
  • String、Hash、List、Set、Sorted Set(ZSet)
  • Bitmap、Bitfield、HyperLogLog、Geo、Stream

89.TCP 滑动窗口的作用是什么?

展开 中等 VIP 网络
  • 滑动窗口会根据接收方的缓冲区剩余空间大小(Window Size)来限制发送方一次能发的未确认数据量
  • 更好的流量控制,以动态的控制窗口可大小
  • 增大了吞吐量,允许发送方连续发多个数据段

90.介绍一下 Reactor 线程模型?

展开 中等 VIP Netty 后端
  • 单 Reactor 单线程:一个线程完成事件多路复用、接受连接、读写与业务处理,简单但扩展性差。
  • 单 Reactor 多线程:Reactor 负责 accept 与事件分发,工作线程池处理业务逻辑,提高并发度。
  • 多 Reactor 多线程(主从):主 Reactor 专职 accept,多个从 Reactor 负责读写与分发到工作线程池,常见于高并发框架。
  • Netty 对应:bossGroup(accept)+ workerGroup(I/O 读写与处理),基于 epoll/kqueue/select 的事件驱动。

91.Java 线程池核心线程数在运行过程中能修改吗?如何修改?

展开

能改。通过 ThreadPoolExecutor 动态调整:

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
executor.setCorePoolSize(20);
executor.setMaximumPoolSize(100);
executor.allowCoreThreadTimeOut(true); // 可选:允许核心线程超时回收

在 Spring 中可用 ThreadPoolTaskExecutor 在启动前配置;运行期需获取底层 ThreadPoolExecutor 再调整。

92.TCP/IP 四层模型是什么?

展开 简单 VIP 网络
  • 应用层(Application):HTTP、DNS、FTP、SMTP、SSH 等
  • 传输层(Transport):TCP、UDP
  • 网络层(Network):IP、ICMP、IGMP、NAT 等
  • 网络接口层(Link / Network Interface):以太网、PPP 等

93.说说 MyBatis 的缓存机制?

展开
  • 一级缓存,SqlSession级别,默认开启
  • 每一个SqlSession会对应创建一个执行器,执行器里会有一个存储键值对的对象,key是根据查询语句和参数确定的
  • 一级缓存在应用层规避了读已提交隔离级别下的不可重复读问题,在一个SqlSession里读不到其他事务已提交的数据
  • 二级缓存是mapper级别,默认关闭,可以自定义实现,实现Cache接口或者用集成包

94.什么是 Spring Boot?

展开 中等 VIP Spring Boot 后端
  • 对 Spring 进行“约定优于配置”的封装,提供自动配置、起步依赖、嵌入式容器与外部化配置,显著降低样板代码与环境搭建成本。
  • 支持可观测性与生产特性(Actuator、健康检查、指标、日志),便于云原生与容器化部署。
  • 与传统 Spring 对比:无需繁琐 XML/JavaConfig 手动装配,专注业务开发。

95.Java 中如何创建多线程?

展开
  • 继承 Thread:重写 run()new Thread().start()
  • 实现 Runnablenew Thread(new Runnable(){...}).start() 或 lambda。
  • 实现 Callable<V>:配合 FutureTaskExecutorService.submit 获取返回值与异常。
  • 线程池:ExecutorServicenewFixedThreadPoolnewCachedThreadPoolThreadPoolExecutor 自定义)。
  • 异步工具:CompletableFuture 组合式异步编程,ForkJoinPool 分治任务。

96.Redis 中跳表的实现原理是什么?

展开 困难 VIP 后端 Redis
  • 跳表是多层有序链表,通过随机层高实现对数期望复杂度的查找/插入/删除(平均 O(log n))。
  • 节点包含多个前进指针,查找自顶层向下逐层推进,最终在最低层定位目标。
  • ZSet 底层通常由“字典(member->score)+ 跳表(按 score 有序)”组成;小集合使用压缩结构以节省内存。
  • 插入时通过随机函数生成层高(常用 p=0.25),维护跨度用于排名/区间查询;支持按分值与按字典序范围查询。

97.Redis 性能瓶颈时如何处理?

展开 中等 VIP 后端 Redis
  • 模型与数据:避免大 Key/大 Value,拆分热 Key,控制集合过大;使用合适数据结构与过期策略。
  • I/O 与协议:Pipeline 批处理、合理批量大小;减少频繁往返;用 Lua 保证原子性并减少网络开销。
  • 持久化与内存:合适的 RDB/AOF 策略,规避高峰期 fork;关注内存碎片率与 eviction 策略;合理 maxmemory
  • 并发与线程:Redis 6+ 支持 I/O 线程;避免阻塞型命令;控制慢查询,监控 slowlog
  • 架构层面:读写分离、主从复制、哨兵高可用、Cluster 分片水平扩展;客户端连接池与重试熔断。
  • 系统调优:网络参数(tcp_backlogsomaxconn)、net.corevm.overcommit_memory 等。

98.OSI 七层模型是什么?

展开 中等 VIP 网络
  1. 应用层(Application Layer)
  • 作用:直接面向用户,提供网络服务的接口。
  • 例子:HTTP、FTP、SMTP、DNS
  • 数据单位:消息(Message)
  1. 表示层(Presentation Layer)
  • 作用:处理数据的表示、编码、压缩、加密等,使不同系统能正确理解数据。
  • 例子:JPEG、GIF、TLS/SSL、JSON 编码、Base64
  • 数据单位:消息(Message)
  1. 会话层(Session Layer)
  • 作用:建立、管理和终止通信会话;同步检查点。
  • 例子:RPC、SQL 会话、NetBIOS
  • 数据单位:消息(Message)
  1. 传输层(Transport Layer)
  • 作用:端到端的可靠(TCP)或不可靠(UDP)数据传输;分段、重传、流量控制、拥塞控制。
  • 例子:TCP、UDP
  • 数据单位:段(Segment)
  1. 网络层(Network Layer)
  • 作用:负责主机到主机的逻辑寻址与路径选择。
  • 例子:IP(IPv4/IPv6)、ICMP、IGMP
  • 数据单位:包(Packet)
  1. 数据链路层(Data Link Layer)
  • 作用:在物理层上提供无差错的数据传输;进行帧定界、差错检测(CRC)。
  • 例子:Ethernet、PPP、HDLC、MAC 地址
  • 数据单位:帧(Frame)
  1. 物理层(Physical Layer)
  • 作用:定义物理媒介、信号、电压、线缆、接口标准等。
  • 例子:RJ45、光纤、IEEE 802.3、双绞线
  • 数据单位:比特(Bit)

99.说说 AQS 吧?

展开 中等 Java并发 Java
  • AbstractQueuedSynchronizer:基于状态值 state 与 CLH 同步队列,提供独占/共享两种获取/释放语义。
  • 关键方法:tryAcquire/tryRelease(独占),tryAcquireShared/tryReleaseShared(共享),配合 CAS + LockSupport.park/unpark 挂起/唤醒线程。
  • 公平/非公平策略:决定获取顺序是否严格 FIFO。
  • 基于 AQS 的组件:ReentrantLockSemaphoreCountDownLatchReentrantReadWriteLockFutureTask 等。

100.Cookie、Session、Token 之间有什么区别?

展开 中等 VIP 网络
  • 存储位置:
    • Cookie:浏览器本地(可 HttpOnlySecureSameSite)。
    • Session:服务端存储会话状态(客户端通常持有 SessionID Cookie)。
    • Token:一般存于客户端(Header/Storage/Cookie),服务端可无状态校验(如 JWT)。
  • 状态性与伸缩:
    • Session 需要共享或粘性会话;Token 天生适合无状态与横向扩展。
  • 安全性:
    • 防 CSRF:优先使用 SameSite 或在 Header 传递 Token;结合 CSRF Token 双重校验。
    • 防 XSS:Cookie 加 HttpOnly;Token 泄露需及时失效(黑名单/短有效期/刷新机制)。
  • 适用场景:
    • 传统站点:Session + Cookie 简单直接。
    • 多端与微服务:JWT/OAuth2 的 Token 更合适(便于网关与下游服务校验)。