🗒️后端面试准备

比尔盖子

|2025-9-1|最后更新: 2025-9-8|
type
status
date
slug
summary
tags
category
icon
password

Java基础

基本数据类型

数字:short,int,long,double,byte
字符:char
布尔:boolean

自动装箱拆箱

装箱:Integer i=1,Integer.valueOf(1)
拆箱:int a = i,i.intValue()

String

不可变因为final修饰,final char value[]
StringBuilder线程不安全,可变
StringBuffer线程安全,速度慢,可变

集合

List,Set,Map,Queue
ArrayList:线程不安全,指定位置插入,元素需要位移。
LinkedList:线程不安全,插入速度快。
HashMap:线程不安全,数组+链表。链表长度大于8,转为红黑树。
HasTable:线程安全,速度慢,基本被淘汰。数组+链表。
ConcurrentHashMap:线程安全,相对于HashTable实行分段加锁。效率上会快一些,底层数据结构还是跟HashMap一样。

线程状态

线程状态
notion image
死锁条件
  • 互斥条件:该资源任意一个时刻只由一个线程占用。
  • 请求与保持条件:一个线程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
  • 循环等待条件:若干线程之间形成一种头尾相接的循环等待资源关系。
预防死锁
  • 破坏请求与保持条件:一次性申请所有的资源。
  • 破坏不剥夺条件:占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
  • 破坏循环等待条件:靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。

锁机制

乐观锁:认为每次访问时不会出问题,采用CAS更新数据。用于读比较多的场景。
悲观锁:认为每次被访问就会出问题,每次操作资源就会上锁。性能开销大,会有死锁问题。用于写比较多的常见。

并发编程

synchronized和reentrantlock,reentrantlock更加灵活。可实现公平锁。
Semaphore:信号量,获取到资源的时候才会继续执行。
CountDownLatch:到0之后开始继续执行。
CyclicBarrier:当一组线程全部到达屏障之后才会继续开始执行,否则都阻塞。
CompletableFuture:异步任务编排,anyOf和Allof并行执行,get方法阻塞。可以指定线程池。

线程池

ThreadPoolExecutor 3 个最重要的参数:
  • corePoolSize : 任务队列未达到队列容量时,最大可以同时运行的线程数量。
  • maximumPoolSize : 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
  • workQueue: 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
ThreadPoolExecutor其他常见参数 :
  • keepAliveTime:当线程池中的线程数量大于corePoolSize ,即有非核心线程(线程池中核心线程以外的线程)时,这些非核心线程空闲后不会立即销毁,而是会等待,直到等待的时间超过了 keepAliveTime才会被回收销毁。
  • unit : keepAliveTime 参数的时间单位。
  • threadFactory :executor 创建新线程的时候会用到。
  • handler :拒绝策略
notion image

垃圾回收

notion image
内存分配原则
  • 对象优先在Eden分配
  • 大对象直接进入老年代
  • 长期存活的对象进入老年代
对象死亡判断方法
  • 引用计数法:对象添加引用计数变量,每次被引用就+1。当引用计数等于0时被回收。
  • 可达性分析法:从GC Root向下寻找,在这棵树上的就不需要被回收。

JVM调优

JVM内存区域
notion image
不得不进行调优的时机,这是最后手段,不建议优先使用。因为参数都是魔法数字,不可持续维护。
  • full gc频繁,老年代太小
  • gc停顿时间太长
  • 系统启动的时候频繁gc,运行稳定之后不gc
排除方法
  • jstat -gc查看堆中分区占用内存
常见策略
  • 内存不够:Xms,Xmx设大点
  • 启动时频繁gc:Xms=Xmx
  • 调整内存区大小比例:survivor区和Eden区大小比率SurvivorRatio,新时代和老年代比例NewRatio
  • 对象过早进入老年代:提升对象老年代年龄
  • 垃圾回收器类型:Serial(串行),Parallel(并行),CMS,G1

设计模式

单例模式:Spring中Bean就是单例。
工厂模式:对象都通过工厂方法new出来,不用关心对象创建过程。
观察者模式/发布-订阅模式:MetaQ和EventBus
责任链:Spring中的Filer多个过滤器依次处理请求

Redis

常见数据结构:string,map,list,set,有序set
作用:分布式锁,限流,消息队列

限流

令牌桶算法:拿到令牌才能访问,定时向令牌桶中放置令牌。

缓存击穿,缓存穿透,缓存雪崩

缓存穿透:无效key即不在数据库里也不在Redis。布隆过滤器,接口限流。
缓存击穿:热点数据在数据库中,不在缓存中。提前预热热点数据。
缓存雪崩:缓存同一时间大面积失效。设置随机过期时间,提前预热。

主从复制

mater负责写,slave负责读
哨兵:多一个哨兵机器用于监听机器下线,选举出一个master。主观下线表示当前哨兵认为下线,客观下线所有哨兵认为该机器下线。
切片机器:适合数据量大的时候,主从复制有太多冗余,将数据切片分散保存。

持久化

AOF(Append Only File)保存每一个操作命令,不存在丢失数据风险,恢复速度慢。
RDB(Redis Database Snapshot)定时保存数据快照,存在丢失数据风险,恢复速度快。
混合模式:结合AOF和RDB的优点。

分布式锁

  • 获取锁,set if not exist,如果key存在则获取失败。
  • 释放锁,删除key。
  • 需要设置过期时间,放在锁释放不了造成死锁。

Dubbo

生产者提供api包,不包括具体实现。消费者引入这个包直接使用。
  1. 注册中心(Registry):生产者在此注册并发布内容,消费者在此订阅并接收发布的内容。
  1. 消费者(Consumer):客户端,从注册中心获取到方法,可以调用生产者中的方法。
  1. 生产者(Provider):服务端,生产内容,生产前需要依赖容器(先启动容器)。
  1. 容器(Container):生产者在启动执行的时候,必须依赖容器才能正常启动(默认依赖的是Spring容器)。
  1. 监控(Monitor):统计服务的调用次数与时间等。

MySql

事务

ACID:原子性,一致性,隔离性,持久性

InnoDb

数据结构
  • 二叉查找树:解决查询时间问题,二分查找
  • AVL平衡树:解决二叉查找树不平衡问题,可能会退化为链表
  • 红黑树:解决AVL旋转耗时问题
  • B树:解决红黑树查询耗时问题,转为多叉查找树。降低树的层级。
  • B+树:子节点用链表相连,非叶子节点不存储数据。

并发带来问题

  • 脏读:A事务回滚了,B事务读了A回滚前的脏数据。
  • 不可重复读:A事务在修改数据,B在修改前和修改后都读了一下,发现不一样。
  • 幻读:B事务在A事务插入一行前读了一下,在插入之后读了一下,发现多了一行。

常见日志

  • binlog:记录每一条更改数据库的SQL
  • general query log:所有查询SQL
  • slow query log:执行时间超过long_query_time的SQL查询
  • redo log和undo log:事务日志

性能优化

  • 分表分库
    • 垂直分表:根据业务类型纵向切分表,根据访问业务,频率切分
    • 水平分表:基于数据的表行进行拆分,将大表拆为几个小表
  • 读写分离
    • 主表写,从表读。从表利用主表的binlog复制数据
    • 主从同步延迟:1)对数据一致性要求高的请求直接路由到主表读。2)提升从库的机器性能。3)延迟读取,等他同步完了
  • 慢查询排查
    • 开启慢查询日志slow_query_log,设置慢查询日志long_query_time
    • select前加上explain
    • 查看type和key,type至少要range以上
      • const通过唯一索引找到
      • range索引范围扫描
      • index全索引扫描
      • all全表扫描

Mybatis

#{}和${}区别是什么?

${}是字符串变量,有sql注入风险
#{}是参数变量,mybatis会将#{}替换为问号,执行前将问号替换为参数

如何分页

  1. 使用RowBounds,内存分页。原理是所有数据都加载到内存,把查询到的分页返回。
  1. 使用物理分页,使用mysql语句中的limit x,y。x是限制几条,y是偏移量。

常用标签

  • 增删改查:insert,delete,update,select
  • resultMap,用于解决java对象和数据库列名不一致问题
  • where,when,if,forEach

SpringBoot

AOP

面向切面编程,可以将跟业务代码无关的逻辑放到AOP中实现。如:日志,权限控制,事务控制。
在方法执行前或者执行后插入代码。

IOC和DI

ioc:将对象的生命周期交给ioc容器管理,用于对象之间解耦
di:依赖注入,存在依赖的两个对象通过依赖注入连接。Autowired和Resource

鉴权和认证

RBAC模型

一个用户有多个角色,一个角色有多个权限。
notion image

表结构

一共5张表。用户表,角色表,权限表。用户和角色关系表。角色和权限关系表。

Spring Security

通用配置
  • 拦截所有需要权限控制的路径,只放开跟登录有关的。
  • 在UsernamePasswordAuthenticationFilter拦截器上自定义自己的拦截逻辑。
第一次登录
  • 接收用户的帐号和密码,跟数据库中核对。
  • 登录成功将生成的token放入redis中,value设置为用户信息
  • 在前端cookie中塞入token
第二次登录
  • 解析cookie中的token,如果在redis中存在则之间返回登录成功。
鉴权
  • 根据用户名查询用户角色和权限,将权限列表塞回给User对象。Spring Security会校验访问的接口路径是否在权限列表中。
  • 使用hasAuthority和hasRole注解控制权限。

定时任务

单机任务
spring的schdule
分布式任务
xxl-job

实时消息推送

  • 轮询
  • SSE:前端开启EventSource文件流,像断断续续的下载
  • WebSocket:双选通信
Loading...