一、源码阅读
HashMap
考察点: HashMap的数据结构、链表、数据均匀分布、线程安全问题
需要理解并熟记的点:
- 数据结构
- HashMap数据为啥使用链表而不是数组?(hash的概率性)
- Java8之前是头插法,为什么
- Java8之后才有尾插法,又为什么
使用头插
会改变链表的上的顺序,但是如果
使用尾插
,在扩容时会保持链表元素原本的顺序,就不会出现链表成环的问题了。
- 在Java7和Java8之间的区别
- Java8之后的链表有红黑树,通过红黑树将原本的O(n)的时间复杂度降低到O(log n)
- hash冲突是怎么发生的及如何解决
- 链表节点插入法有哪些以及为什么用这些插入法
- hashCode()、equals方法重写
- 如何扩容
- 扩容的因素(Capacity、LoadFactor)
- 扩容分为2步,新的Entry空数组(原数组的2倍)、ReHash(重新hash的原因是重新计算位置,Hash的公式:index = HashCode(Key) & (Length - 1))
- 为啥初始化的容量是16? 为了实现均匀分布。
因为在使用是2的幂的数字的时候,Length-1的值是所有二进制位全为1,这种情况下,index的结果等同于HashCode后几位的值。只要输入的HashCode本身分布均匀,Hash算法的结果就是均匀的
ThreadLocal
考察点: 线程安全、数据隔离
实际应用场景: 数据源切换、大数据处理任务组、事务隔离(Spring)、上下文
需要理解并熟记的点:
- 主要作用及在哪些场景下使用
- 底层实现原理
- 底层数据结构
- 如何共享线程的ThreadLocal对象
- ThreadLocal在使用过程中,会出现哪些问题?为什么会出现?如何解决?
Spring采用Threadlocal的方式,来保证单个线程中的数据库操作使用的是同一个数据库连接,同时,采用这种方式可以使业务层使用事务时不需要感知并管理connection对象,通过传播级别,巧妙地管理多个事务配置之间的切换,挂起和恢复。
ConcurrentHashMap & HashTable
考察点: ConcurrentHashMap& HashTable的底层实现、线程安全问题、锁
需要理解并熟记的点:
- ConcurrentHashMap如何实现线程安全的
- ConcurrentHashMap的数据结构
- ConcurrentHashMap的put和get操作
- 在Java7和Java8之间的区别
- Hashtable、ConcurrentHashMap和HashMap的区别
- ConcurrentHashMap实现原理
- CAS是什么?自旋是什么?
- ABA是什么? ABA有哪些问题及如何解决
- 什么是锁升级?
JVM 使用了锁升级的优化方式,就是先使用
偏向锁
优先同一线程然后再次获取锁,如果失败,就升级为
CAS 轻量级锁
,如果失败就会短暂
自旋
,防止线程被系统挂起。最后如果以上都失败就升级为
重量级锁
。
- Java7采用了分段锁技术,Java8采用了CAS + synchronized
CAS 操作的流程是,线程在读取数据时不进行加锁,在准备写回数据时,比较原值是否修改,若未被其他线程修改则写回,若已被修改,则重新执行读取流程。
ArrayList
考察点: ArrayList的底层实现、线程安全
需要理解并熟记的点:
- 实现原理
- 在Java7和Java8之间的区别
- 数组的添加和删除全部是copy数据,所以效率非常低且线程不安全
volatile
考察点: JMM、缓存一致性、指令重排序、可见性
需要理解并熟记的点:
- JMM
- 可见性问题: 什么是可见性问题,如何发生的及如何去解决
- volatile 做了哪些工作
- MESI缓存一致性协议是什么
- 什么是指令重排序?如何禁止指令重排?
- 什么是内存屏障?
- volatile与synchronized的区别
- 有哪些应用场景
synchronized
考察点: 原理、锁
https://juejin.im/post/6844904196676780040
需要理解并熟记的点:
- 在哪些场景会使用
- 如何实现加锁的(如何保证线程安全的)
- synchronized如何做到有序性、可见性、原子性
- synchronized底层是如何实现的
- 锁升级、偏向锁、轻量级锁、重量级锁
- synchronized和Lock的区别
- Java对象在JVM的内存中分为哪三块区域

synchronized 获取锁的方式,JVM 使用了锁升级的优化方式,就是先使用偏向锁优先同一线程然后再次获取锁,如果失败,就升级为 CAS 轻量级锁,如果失败就会短暂自旋,防止线程被系统挂起。最后如果以上都失败就升级为重量级锁。
参考: https://mp.weixin.qq.com/s/WtAdXvaRuBZ-SXayIKu1mA
锁
考察点: 公平锁、非公平锁、乐观锁、悲观锁
需要理解并熟记的点:
- 公平锁、非公平锁、乐观锁、悲观锁的解释
- CAS操作
- 分布式锁解决库存超卖
- 实例: ReentrantLock中有公平锁和非公平锁的相关实现
- AQS关键对象:
state、加锁线程、等待队列
根据这三个对象如果可以解释公平锁和非公平锁最好 - CAS是乐观锁的一种实现方式,是一种轻量级锁,JUC 中很多工具类的实现就是基于 CAS 的。
- synchronized是悲观锁的表现
- CAS 是怎么实现线程安全的?
CAS 是怎么实现线程安全的?
线程在读取数据时不进行加锁,在准备写回数据时,先去查询原值,操作的时候比较原值是否修改,若未被其他线程修改则写回,若已被修改,则重新执行读取流程。
线程安全问题
考察点:线程安全问题实际上是数据一致性问题
- 如何实现多线程
- 线程池
后端面试题
https://juejin.im/post/6844904161612398600
二、主流技术
Redis
考察点:
场景: 秒杀系统、应用首页缓存
需要理解并熟记的点:
- Redis和Memcached的区别
- Redis有哪些数据结构及适用的场景
- 布隆过滤器(避免缓存击穿)
- 如何使用Redis实现异步队列
- 如何实现1:N的消息队列?方案有无缺点
- 如何实现延时队列
- Redis是如何做持久化的?服务器主从数据如何交互?
- RDB的原理(fork&cow[copy on write])
- 什么是Pipeline
- Redis的同步机制
- Redis集群有哪些?集群的高可用如何保证及集群的原理
- Redis Sentinal 着眼于高可用;Redis Cluster 着眼于扩展性
Redis · 第二战
场景: 缓存雪崩、击穿、穿透
需要理解并熟记的点:
- 缓存雪崩、击穿、穿透的各自指什么以及如何解决
- Redis雪崩如何处理
- 如何让缓存数据均匀的分布在Redis集群中的每台节点
- 布隆过滤器(避免缓存击穿)
Redis · 第三站之布隆过滤器
场景: 缓存击穿
需要理解并熟记的点:
- 布隆过滤器原理
- 布隆过滤器缺点
- 布隆过滤器实现
Redis · 第四站
场景: Redis哨兵、持久化、主从、手撕LRU
需要理解并熟记的点:
Redis为什么快
- Redis高可用可以从哪些方面保证
- RDB和AOF各自的优缺点
- Redis的内存淘汰机制
- Redis的惰性删除是什么
Redis · 第五站
场景: Redis双写一致性、并发竞争、线程模型
需要理解并熟记的点:
- 多个系统同时操作(并发)Redis会带来什么问题?如何解决?
- 缓存与DB如何保证数据一致性问题
- 最经典的缓存+数据库读写的模式 (Cache Aside Pattern)
- Redis的线程模型是什么(
file event handler
)
Redis的线程模型:
Redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 Redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 Socket,根据 Socket 上的事件来选择对应的事件处理器进行处理。
文件事件处理器的结构包含 4 个部分:
1.多个 Socket
2.IO 多路复用程序
3.文件事件分派器
4.事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)
多个 Socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 Socket,会将 Socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,把该事件交给对应的事件处理器进行处理。

实现Redis分布式锁
考察点: 应用场景、方案设计、高并发、分布式锁、可重入性
需要理解并熟记的点:
- 如何实现分布式锁?
- 哪种情况会出现死锁?如何解决?
- redisson的锁实现了可重入性,什么是可重入性?
消息队列
考察点: 应用场景、方案设计、数据一致性、事务
需要理解并熟记的点:
- MQ脑裂是如何发生的
- 消息队列的使用场景(异步、削峰、解耦)
- 使用消息队列会出现哪些问题以及如何解决
- 系统复杂性——重复消费、消息丢失、消息的顺序消费
- 数据一致性问题
- 可用性问题
- 分布式事务、重复消费、顺序消费
- 重复消费的产生是因为消息队列的重试机制,解决方法就是接口保持幂等
- 如何保证幂等?强校验、弱校验、流水表等等
- 如何保证队列的顺序消费?顺序消费只要保证一个消费者消费就可以了,原理就是同一业务主键统一放到一个队列中生产和消费即可
- 重复消费的产生是因为消息队列的重试机制,解决方法就是接口保持幂等
ZK
考察点: 场景、方案设计、分布式锁
需要理解并熟记的点:
- 如何实现分布式锁?(解决库存超卖等问题)
- 使用场景:
- 服务注册与订阅(共用节点)
- 分布式通知(监听znode)
- 服务命名(znode特性)
- 数据订阅、发布(watcher)
- 分布式锁(临时节点)
- zk是什么
JVM
考察点:
需要理解并熟记的点:
- JVM的回收机制
- 有哪些回收算法
- 分代回收
三、分布式
分布式事务
需要理解并熟记的点:
- 有哪些分布式事务解决方案
- 2pc(两段式提交)【最简单】
- 3pc(三段式提交)
- TCC(Try、Confirm、Cancel)
- 最大努力通知
- XA
- 本地消息表(ebay研发出的)【较为常用】
- 半消息/最终一致性(RocketMQ)【较为常用】
- 分布式事务有哪些问题点
- 长时间锁定数据库资源,导致系统的响应不快,并发上不去。
- 网络抖动出现脑裂情况,导致事物参与者,不能很好地执行协调者的指令,导致数据不一致。
- 单点故障:例如事物协调者,在某一时刻宕机,虽然可以通过选举机制产生新的Leader,但是这过程中,必然出现问题,而TCC,只有强悍的技术团队,才能支持开发,成本太高。
四、数据库
索引
考察点: 基础数据结构(Hash、B+、二叉树)
需要理解并熟记的点:
- 索引有哪些数据结构(Hash、B+)
- 回表
- MySQL基础的存储结构——页
- 覆盖索引 https://juejin.im/post/6844903967365791752
- 索引的最左匹配原则
- 聚簇索引与非聚簇索引 https://cloud.tencent.com/developer/article/1541265
- 唯一索引普通索引选择难题
Mysql各种索引区别:
普通索引:最基本的索引,没有任何限制
唯一索引:与"普通索引"类似,不同的就是:索引列的值必须唯一,但允许有空值。
主键索引:它 是一种特殊的唯一索引,不允许有空值。
全文索引:仅可用于 MyISAM 表,针对较大的数据,生成全文索引很耗时好空间。
组合索引:为了更多的提高mysql效率可建立组合索引,遵循”最左前缀“原则。
数据库调优
需要理解并熟记的点:
- SQL调优
- 排除缓存干扰
- Explain
- 覆盖索引
- 联合索引
- 最左匹配原则
- 索引下推
- 唯一索引(change buffer)
- 前缀索引
- 条件字段函数操作(饮食类型转换)
- 隐式字符编码转换
- flush
四、线上排查经验
- 接口响应过慢排除(分布式系统)
- 使用阿里开源工具arthas排查线上问题
五、业务方案设计
- 系统异构方案
- 防并发方案设计
- 多版本兼容方案(运维+业务)
- 分库分表方案
- 数据同步方案
- 行转列存储方案设计
- 和三方系统如何保证数据一致性
六、心理战
调整好心态
七、由点到线到面
