Skip to main content

综合101-120

101. 什么是分库分表?分库分表有哪些类型(或策略)?

展开 简单 VIP 后端 MySQL 数据库

分库分表是将原来集中存储在一个数据库中的数据分散存储到多个数据库/表中,以应对海量数据带来的性能问题。

分库分表类型:

  • 垂直分库:按业务模块将不同表分散到不同数据库
  • 垂直分表:将一个表的不同字段分散到不同表中
  • 水平分库:将同一个表的数据按某种规则分散到不同数据库
  • 水平分表:将同一个表的数据按某种规则分散到不同表中

分片策略:

  • 范围分片:按ID范围、时间范围等
  • 哈希分片:对分片键进行哈希运算
  • 目录分片:维护分片映射关系表
  • 一致性哈希:解决节点动态增减问题

102. MyBatis 中 #{} 和 ${} 的区别是什么?

展开 简单 VIP 后端 MyBatis

#{}(推荐):

  • 预编译处理,防止SQL注入
  • 参数会被当作字符串,自动加上引号
  • 底层使用PreparedStatement的占位符

${}(谨慎使用):

  • 字符串替换,直接拼接到SQL中
  • 存在SQL注入风险
  • 适用于动态表名、列名等场景
-- #{} 示例
SELECT * FROM user WHERE id = #{id}
-- 实际执行:SELECT * FROM user WHERE id = ?

-- ${} 示例
SELECT * FROM ${tableName} WHERE id = #{id}
-- 实际执行:SELECT * FROM user WHERE id = ?

103. Java 中的 final 关键字是否能保证变量的可见性?

展开 中等 Java并发 Java

final不能保证变量的可见性,但有特殊语义:

final的内存语义:

  • 对final字段的写入会在构造函数返回前完成
  • 禁止final字段写入与构造函数返回重排序
  • 读取final字段不会与读取该字段的对象引用重排序

可见性保证需要:

  • volatile:保证变量在多线程间的可见性
  • synchronized:同步块保证可见性
  • happens-before规则
class Example {
private final int x;
private volatile int y; // 需要volatile保证可见性

public Example(int x) {
this.x = x; // final保证构造完成后的正确读取
}
}

104. Redis 的 hash 是什么?

展开 中等 VIP 后端 Redis

Redis Hash是一个键值对集合,类似于Java中的HashMap。

底层实现:

  • ziplist(压缩列表):元素较少时使用,内存紧凑
  • hashtable(哈希表):元素较多时使用,查询高效

切换条件:

  • hash-max-ziplist-entries:最大元素数量(默认512)
  • hash-max-ziplist-value:最大值长度(默认64字节)

常用命令:

HSET user:1 name "张三" age 25
HGET user:1 name
HMGET user:1 name age
HGETALL user:1
HDEL user:1 age

应用场景:

  • 用户信息存储
  • 商品属性存储
  • 配置信息管理

105. 从网络角度来看,用户从输入网址到网页显示,期间发生了什么?

展开 困难 VIP 网络

完整流程:

  1. URL解析:浏览器解析URL,提取协议、域名、路径
  2. DNS解析
    • 浏览器缓存 → 系统缓存 → 路由器缓存 → ISP DNS → 根域名服务器
    • 递归/迭代查询获取IP地址
  3. 建立TCP连接:三次握手建立连接
  4. HTTPS握手(如果是HTTPS):TLS/SSL握手
  5. 发送HTTP请求:构造并发送HTTP请求报文
  6. 服务器处理:Web服务器接收、处理请求
  7. 返回HTTP响应:服务器返回响应报文
  8. 浏览器解析
    • 解析HTML构建DOM树
    • 解析CSS构建CSSOM树
    • 执行JavaScript
    • 构建渲染树
  9. 页面渲染:布局、绘制、合成
  10. 断开连接:四次挥手关闭连接

106. Dubbo 和 Spring Cloud Gateway 有什么区别?

展开 困难 VIP 后端 分布式 Spring Cloud Dubbo

本质区别:

  • Dubbo:RPC框架,服务间直接调用
  • Spring Cloud Gateway:API网关,统一入口

Dubbo特点:

  • 基于接口的RPC调用
  • 支持多种序列化协议
  • 内置负载均衡、服务发现
  • 适合内部服务调用

Spring Cloud Gateway特点:

  • 基于Spring WebFlux响应式编程
  • 路由转发、过滤器链
  • 限流、熔断、监控
  • 适合外部请求入口

使用场景:

  • Dubbo:微服务内部通信
  • Gateway:外部请求统一处理、路由分发

可以结合使用: Gateway作为统一入口,内部使用Dubbo进行服务调用。

107. 什么是 Java 中的原子性、可见性和有序性?

展开 困难 Java并发 Java

并发编程三大特性:

1. 原子性(Atomicity)

  • 操作不可分割,要么全部执行要么全部不执行
  • Java保证:基本数据类型读写(long/double除外)
  • 解决方案:synchronized、Lock、原子类(AtomicInteger)

2. 可见性(Visibility)

  • 一个线程修改变量后,其他线程能立即看到
  • 问题:CPU缓存导致数据不一致
  • 解决方案:volatile、synchronized、final

3. 有序性(Ordering)

  • 程序执行顺序按代码顺序执行
  • 问题:编译器和CPU优化可能重排序
  • 解决方案:volatile、synchronized、happens-before规则
class Example {
private volatile boolean flag = false; // 保证可见性和有序性
private final AtomicInteger count = new AtomicInteger(0); // 保证原子性

public synchronized void update() { // 三种特性都保证
count.incrementAndGet();
flag = true;
}
}

108. 线程和进程有什么区别?

展开 中等 VIP 操作系统 计算机基础

定义:

  • 进程:操作系统资源分配的基本单位
  • 线程:CPU调度的基本单位

主要区别:

对比项进程线程
内存空间独立地址空间共享进程地址空间
资源开销创建、切换开销大创建、切换开销小
通信方式IPC(管道、消息队列、信号量)共享内存、同步原语
安全性崩溃不影响其他进程一个线程崩溃可能影响整个进程
系统调用fork()pthread_create()

Java中的体现:

// 进程级别
ProcessBuilder pb = new ProcessBuilder("java", "-jar", "app.jar");
Process process = pb.start();

// 线程级别
Thread thread = new Thread(() -> {
// 线程任务
});
thread.start();

109. 说说你知道的几种 I/O 模型

展开 中等 VIP Netty 后端

五种I/O模型:

1. 阻塞I/O(Blocking I/O)

  • 线程阻塞等待数据准备和复制
  • 简单直观,但并发性差

2. 非阻塞I/O(Non-blocking I/O)

  • 立即返回,需要轮询检查状态
  • CPU利用率低,效率不高

3. I/O多路复用(I/O Multiplexing)

  • select/poll/epoll监听多个文件描述符
  • 单线程处理多个连接,高并发

4. 信号驱动I/O(Signal-driven I/O)

  • 数据准备好时发送信号通知
  • 实际应用较少

5. 异步I/O(Asynchronous I/O)

  • 数据复制完成后通知应用程序
  • 真正的异步,性能最优

Java实现:

// BIO
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept(); // 阻塞

// NIO
Selector selector = Selector.open();
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false); // 非阻塞

// AIO(NIO.2)
AsynchronousServerSocketChannel server =
AsynchronousServerSocketChannel.open();

110. MyBatis 与 Hibernate 有哪些不同?

展开 中等 VIP 后端 MyBatis

主要区别:

对比项MyBatisHibernate
类型半自动化ORM全自动化ORM
SQL控制手写SQL,灵活控制自动生成SQL
学习曲线相对简单相对复杂
性能优化手动优化SQL依赖工具和配置
数据库移植需要修改SQL良好的数据库无关性
缓存机制一级、二级缓存强大的缓存体系

MyBatis优势:

  • SQL可控性强,便于优化
  • 轻量级,学习成本低
  • 适合复杂查询和报表

Hibernate优势:

  • 开发效率高
  • 对象化程度高
  • 数据库无关性好

选择建议:

  • 复杂业务逻辑、性能要求高:MyBatis
  • 快速开发、简单CRUD:Hibernate

111. 什么是 Java 内存模型(JMM)?

展开 困难 Java并发 Java

JMM定义: Java内存模型定义了Java程序中变量的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量的底层细节。

内存结构:

  • 主内存:所有线程共享,存储变量的主副本
  • 工作内存:每个线程私有,存储变量的本地副本

八种操作:

  1. lock:锁定主内存变量
  2. unlock:释放主内存变量
  3. read:从主内存读取到工作内存
  4. load:将read的值放入工作内存变量副本
  5. use:将工作内存变量传递给执行引擎
  6. assign:将执行引擎的值赋给工作内存变量
  7. store:将工作内存变量传送到主内存
  8. write:将store的值写入主内存变量

happens-before规则:

  • 程序次序规则
  • 锁定规则
  • volatile变量规则
  • 传递性规则
  • 线程启动规则
  • 线程终止规则

112. Redis 和 Memcached 有哪些区别?

展开 中等 VIP 后端 Redis

主要区别:

对比项RedisMemcached
数据类型丰富(String、Hash、List、Set、ZSet)只支持简单String
持久化支持RDB、AOF不支持
分布式支持集群、主从客户端分片
线程模型单线程+IO多路复用多线程
内存使用更高效的内存使用简单的内存分配
功能特性发布订阅、事务、Lua脚本功能简单

Redis优势:

  • 数据结构丰富
  • 持久化能力
  • 功能强大

Memcached优势:

  • 多线程性能好
  • 内存使用简单高效
  • 稳定可靠

使用场景:

  • Redis:复杂数据结构、持久化需求
  • Memcached:简单缓存、高并发读写

113. 什么是物理地址,什么是逻辑地址?

展开 中等 VIP 操作系统

逻辑地址(Virtual Address):

  • 程序运行时CPU产生的地址
  • 相对于程序起始位置的偏移地址
  • 需要通过地址转换机制转为物理地址

物理地址(Physical Address):

  • 内存中真实的存储地址
  • CPU访问内存时实际使用的地址
  • 直接对应内存条上的存储单元

地址转换过程:

  1. 编译时:源代码 → 逻辑地址
  2. 装载时:逻辑地址 → 线性地址(分段)
  3. 运行时:线性地址 → 物理地址(分页)

转换机制:

  • 分段:逻辑地址 = 段选择子 + 段内偏移
  • 分页:线性地址 = 页号 + 页内偏移
  • MMU:内存管理单元负责地址转换

优势:

  • 程序重定位
  • 内存保护
  • 虚拟内存支持

114. 说说什么是 API 网关?它有什么作用?

展开 中等 VIP 后端 分布式 Spring Cloud

API网关定义: API网关是微服务架构中的统一入口,负责请求路由、组合和协议转换。

主要作用:

1. 请求路由

  • 根据请求路径、方法等路由到具体服务
  • 负载均衡和故障转移

2. 协议转换

  • HTTP/HTTPS转换
  • REST API到RPC调用

3. 安全认证

  • 统一的身份验证和授权
  • API密钥管理

4. 限流熔断

  • 接口限流保护后端服务
  • 熔断机制防止故障扩散

5. 监控日志

  • 统一的访问日志
  • 性能监控和分析

6. 请求/响应处理

  • 请求参数校验
  • 响应数据格式化

常见实现:

  • Spring Cloud Gateway
  • Zuul
  • Kong
  • Nginx+Lua

架构模式:

客户端 → API网关 → 微服务A/B/C

115. 什么是 Java 的 CAS(Compare-And-Swap)操作?

展开 中等 Java并发 Java

CAS定义: Compare-And-Swap是一种无锁的原子操作,比较内存位置的值与期望值,如果相等则更新为新值。

操作过程:

boolean compareAndSwap(int* memory, int expected, int newValue) {
if (*memory == expected) {
*memory = newValue;
return true;
}
return false;
}

Java实现:

AtomicInteger atomicInt = new AtomicInteger(0);

// CAS操作
boolean success = atomicInt.compareAndSet(0, 1);

// 底层实现(简化)
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}

优势:

  • 无锁操作,避免线程阻塞
  • 高性能,适合高并发场景
  • 避免死锁问题

问题:

  • ABA问题:值从A变B再变A,CAS检测不到
  • 循环时间开销:自旋等待可能消耗CPU
  • 只能保证单个变量原子性

解决方案:

  • AtomicStampedReference解决ABA问题
  • LongAdder优化高并发累加场景

116. Select、Poll、Epoll 之间有什么区别?

展开 中等 VIP 操作系统

I/O多路复用机制对比:

Select:

  • 基于位图,最大支持1024个文件描述符
  • 每次调用需要遍历所有文件描述符
  • 需要在用户态和内核态间复制数据
  • 跨平台兼容性好

Poll:

  • 基于链表,没有文件描述符数量限制
  • 仍需要遍历所有文件描述符
  • 性能与select类似
  • 解决了select的数量限制问题

Epoll(Linux特有):

  • 基于事件驱动,只关注活跃的文件描述符
  • 支持百万级连接
  • 内核维护就绪队列,避免轮询
  • 支持边缘触发(ET)和水平触发(LT)

性能对比:

特性SelectPollEpoll
最大连接数1024无限制无限制
时间复杂度O(n)O(n)O(1)
内存复制需要需要不需要
跨平台否(Linux)

使用场景:

  • Select/Poll:连接数较少,需要跨平台
  • Epoll:高并发服务器,Linux环境

117. 什么是 MyBatis-Plus?它有什么作用?它和 MyBatis 有哪些区别?

展开 中等 VIP 后端 Mybatis-plus 编程导航

MyBatis-Plus定义: MyBatis-Plus是MyBatis的增强工具,在MyBatis基础上只做增强不做改变。

主要功能:

1. 代码生成器

  • 自动生成Entity、Mapper、Service、Controller
  • 支持模板自定义

2. CRUD接口

// 继承BaseMapper即可获得CRUD能力
public interface UserMapper extends BaseMapper<User> {
}

// 使用示例
userMapper.selectById(1);
userMapper.insert(user);
userMapper.updateById(user);

3. 条件构造器

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1)
.like("name", "张")
.orderByDesc("create_time");
List<User> users = userMapper.selectList(wrapper);

4. 分页插件

Page<User> page = new Page<>(1, 10);
Page<User> result = userMapper.selectPage(page, wrapper);

与MyBatis区别:

特性MyBatisMyBatis-Plus
基础功能需要手写XML/注解提供通用CRUD
代码量较多大幅减少
学习成本
自定义SQL完全自由保持MyBatis特性
扩展性原生支持在MyBatis基础上扩展

优势:

  • 开发效率高
  • 减少重复代码
  • 保持MyBatis灵活性
  • 丰富的插件生态

118. 为什么 Java 中的 ThreadLocal 对 key 的引用为弱引用?

展开 中等 VIP Java并发 Java

ThreadLocal内部结构:

// ThreadLocalMap内部类
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k); // ThreadLocal作为key,使用弱引用
value = v;
}
}

使用弱引用的原因:

1. 防止内存泄漏

  • 如果使用强引用,ThreadLocal对象无法被GC回收
  • 线程长时间运行时,会导致ThreadLocal对象堆积

2. 自动清理机制

  • ThreadLocal对象被GC后,Entry的key变为null
  • ThreadLocalMap在get/set/remove时会清理key为null的Entry

内存泄漏风险:

public class ThreadLocalExample {
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

public void test() {
threadLocal.set("value");
// 如果忘记remove(),value对象可能无法回收
// threadLocal.remove(); // 最佳实践
}
}

最佳实践:

  1. 使用后及时调用remove()
  2. 在finally块中清理
  3. 使用try-with-resources模式

注意事项:

  • 弱引用只是减少了ThreadLocal对象的泄漏
  • value仍可能泄漏,需要手动清理
  • 线程池环境下尤其要注意清理

119. 编译执行与解释执行的区别是什么?JVM 使用哪种方式?

展开 中等 VIP JVM Java

执行方式对比:

编译执行:

  • 源代码一次性翻译成机器码
  • 执行前需要完整编译
  • 执行速度快,但启动慢
  • 代表:C、C++、Go

解释执行:

  • 逐行翻译并执行源代码
  • 不需要预编译
  • 启动快,但执行速度慢
  • 代表:Python、JavaScript(V8前)

JVM的执行方式:

混合模式(HotSpot JVM):

Java源码 → 字节码(javac编译)

解释执行(解释器)

热点检测(Profiler)

编译执行(JIT编译器)

执行流程:

  1. 字节码解释:初始通过解释器执行
  2. 热点检测:识别频繁执行的代码
  3. JIT编译:热点代码编译为本地机器码
  4. 优化执行:直接执行机器码

JIT编译器类型:

  • C1(Client编译器):快速编译,优化较少
  • C2(Server编译器):深度优化,编译时间长
  • 分层编译:结合C1和C2的优势

优势:

  • 启动快:解释执行提供快速启动
  • 运行快:JIT编译提供高性能
  • 跨平台:字节码平台无关

120. Redis 支持事务吗?如何实现?

展开 中等 VIP 后端 Redis

Redis事务特点: Redis支持简单的事务,但与传统数据库事务有所不同。

事务命令:

MULTI      # 开始事务
EXEC # 执行事务
DISCARD # 取消事务
WATCH # 监控键值
UNWATCH # 取消监控

使用示例:

MULTI
SET key1 "value1"
SET key2 "value2"
INCR counter
EXEC

事务特性:

1. 原子性

  • 事务中的命令要么全部执行,要么全部不执行
  • 但不支持回滚,错误命令会被跳过

2. 隔离性

  • 事务执行期间不会被其他客户端命令打断
  • 但不保证一致性读

3. 一致性

  • 事务执行前后,数据保持一致状态

4. 持久性

  • 取决于Redis的持久化配置

乐观锁实现:

WATCH key1
val = GET key1
MULTI
SET key1 newval
EXEC # 如果key1被修改,事务失败

限制:

  • 不支持嵌套事务
  • 不支持回滚操作
  • 语法错误会导致整个事务失败
  • 运行时错误不会中断事务

适用场景:

  • 批量操作
  • 原子性更新多个键
  • 配合WATCH实现乐观锁