JAVA后端开发面试宝典
2025-03-12 13:41:56 0 举报
AI智能生成
全方位总结java面试方向,试试更新
作者其他创作
大纲/内容
Java基础知识
数据结构
ArrayList
底层为:数组+int(size)
达到阈值后进行扩容,如果能预先知道数量最好给定初始容量,否则扩容可能浪费内存空间
遍历、新增、删除都是直接曹祖数组,删除新增可能会进行copy数组
LinkedList
底层为:Node对象(data,next)
遍历时需要从前到后一次查找,删除新增比较快
HashMap
底层为:数组+链表(或红黑树)
每一个Key进来后进行Hash,然后通过位运算映射到Hash数组上,当Hash位运算后的下标冲突时,会在这个位置产生一个
链表,当链表达到8位的时候会转化红黑树,红黑树数组达到6位时会转化为链表
链表,当链表达到8位的时候会转化红黑树,红黑树数组达到6位时会转化为链表
扩容:HashMap位数都是2的次方,这是由于Hash找位算法决定的。当HashMap数据容量达到(数组长度*加载因子)时就
会考虑扩容
会考虑扩容
为什么选择红黑树而不是val,b,b+呢?(红黑树内存性能比b,b+好,删除性能比val好)
为什么链表->红黑树 与 红黑树->链表 分别是8和6而不是一样?(8是红黑树与链表的性能分界点,不都取8是因为如果hash冲突在8附近容易不断转换)
为什么加载因子时0.75呢(泊松分布有关)
为什么初始容量和扩容都是2的倍数呢 ((n-1)&hash算法决定 n-1 为奇数,在二进制中更容易分散)
为什么链表->红黑树 与 红黑树->链表 分别是8和6而不是一样?(8是红黑树与链表的性能分界点,不都取8是因为如果hash冲突在8附近容易不断转换)
为什么加载因子时0.75呢(泊松分布有关)
为什么初始容量和扩容都是2的倍数呢 ((n-1)&hash算法决定 n-1 为奇数,在二进制中更容易分散)
ConcurrentHashMap
底层:数组+链表(或红黑树),hash使用cas比较,其他地方使用synchronized加锁
CopyOnWriteArrayList
底层:多个副本数组,新增、修改、删除都会copy数组副本到volatile修饰的数组(保证可见性)。因此新增、修改、删除消耗很大,一般用于增删改少而查询很多的并发场景
BlockingQueue
ArrayBlockingQueue
LinkedBlockingQueue
多线程
线程
线程是cpu执行的最小单元。有单独的计数器,线程间数据可以共享
单核状态下多线程,cpu不断切换运行,会有上下文切换,因此并不是线程越多越好
线程状态:New,Runable,Running,Blocked,Terminated
线程池
线程池7个参数
核心线程数
计算密集型(CPU核心数+1)
IO密集型(2CPU核心数+1)或者 (CPU核心数*(CPU执行时间+线程等待时间)/CPU执行时间)
最大线程数
等待队列
线程保持时间
线程保持时间单位
拒绝策略
线程创建工厂
创建流程
1、任务来了,现有线程数<核心线程数,那么新增线程
2、现有线程数>核心线程数,并且<最大线程数,那么也新增线程
3、现有线程数>最大线程数,进入等待队列
4、如果等待队列满了,那么进入拒绝策
5、线程任务执行完了,如果有空余的线程,那么等待时间>= 线程保持时间,线程数释放到只有核心线程数个数
ThreadPoolExecuter实现原理
SchedulePoolExecuter实现原理
最小堆
JUC工具包
CountDownLuach
Semaphore
JMM
AQS(底层原理很重要)
java很多并发处理都继承他
CAS
直接操作进行比较替换数据,替换成功返回true
synchronized
升级过程
1、无锁(无线程操作持有操作下)
2、偏向锁(同一线程重复执行情况下效率增加)
3、轻量级锁(CAS自旋)
4、重量级锁(自旋结束后还没获取到锁,那么直接进入mutex lock)
volatile
无法保证原子性,可以保证有序性和一致性
禁止指令重排序
保证可见性
JVM
启动参数
内存区域
堆
java对象存放内存,个线程共享
栈
java运行指令存放,线程独有
方法区
类信息,常量,静态变量
程序计数器
程序运行记录,cpu切换时读取记录,线程独有
本地方法栈
native所有
类加载
加载过程
双亲委派
GC
CMS
PreNew
G1
ZGC
调优命令
jmap(分析内存占用)
jmap -heap [pid]
#dump内存日志
jmap -dump:format=b,file=[filename.prof] [pid]
jmap -dump:format=b,file=[filename.prof] [pid]
#查看对象分布信息
jmap -histo [pid]
jmap -histo [pid]
jstat(分析gc)
#[ms]:多少毫秒打印一次 ,[times]打印多少次
jstat -gc [pid] [ms] [times]
jstat -gc [pid] [ms] [times]
jstack(分析线程运行)
jstack [pid] >> [file.text]
Arthas
阿里巴巴JVM性能调优工具
Spring
IOC
AOP
源码学习
事务
Springboot
SpringMVC
Mybatis
动态代理
数据解析
网络编程
tcp
三次握手四次挥手
http
https
加密过程
socket
read
BIO,阻塞线程
select/poll
读写非阻塞,连接线程循环遍历所有连接,有内核态和用户态的切换
读写线程和连接线程分离,连接线程阻塞,读写非阻塞
读写线程和连接线程分离,连接线程阻塞,读写非阻塞
epoll
读写非阻塞,连接线程回调中处理判断是否有数据,相较于select减少了线程遍历的浪费,
没有fd限制
没有fd限制
udp
非可靠连接
可发送广播、多播
netty
常用粘包处理器
分隔符解码器:FixedLengthFrameDecoder
分隔符解码器:DelimiterBasedFrameDecoder
header中有长度定义数据长度:LengthFieldBasedFrameDecoder
心跳
IdleStateHandler
kafka
常用命令
创建topic
生产
消费
查看group消费情况
查看topic
常用配置
broker配置
生产者配置
消费者配置
系统架构
broker
处理消息的服务器
producer
生产者,生产消息方,属于客户端,需要连接broker
consumer
消费者,消费消息方,属于客户端,需要连接broker
topic
主题,发送消息的逻辑单位,一种业务可以定义一个topic,
生产、消费都需要按照topic处理
生产、消费都需要按照topic处理
patition
每个topic对应多个patition,topic是逻辑单位,patition就是
topic下的多个真实队列,一个topic有多少个patition就可以实现多少并发生产和消费
topic下的多个真实队列,一个topic有多少个patition就可以实现多少并发生产和消费
消费者的个数不能超过patition个数,超过了也没任何用。
消费者=patition,那么每个消费者对应一个patition,减少消费者时会reblance
消费者<patition,一个消费者可能对应多个patition,当新增消费者或者减少消费者时会出现reblance
消费者=patition,那么每个消费者对应一个patition,减少消费者时会reblance
消费者<patition,一个消费者可能对应多个patition,当新增消费者或者减少消费者时会出现reblance
group
每个 consumer 都属于一个 consumer group,每条消息只能被 consumer group 的一个 Consumer 消费,但可以被多个 consumer group 消费。
replica
副本,每一个主题都需要定义有副本,副本会单独存放topic下数据
防止数据丢失,存放逻辑按照patition处理
防止数据丢失,存放逻辑按照patition处理
message
消息,kafka中最基本的传递对象,有固定格式
segment
真实存储数据的地方,每个patition会有多段segment,segment中存放的是消息。
当一个segment中存放的数据超过配置的大小阈值后,会重新新建一个segment,
当一个segment中存放的数据超过配置的大小阈值后,会重新新建一个segment,
offset
一个连续的用于定位被追加到分区的每一个消息的序列号,最大值为64位的long大小,19位数字字符长度。
当一个topic的group下消费到某个消息时,就记录这个消息的序列号,该序列号记录到了一个固定topic中
当一个topic的group下消费到某个消息时,就记录这个消息的序列号,该序列号记录到了一个固定topic中
elasticsearch
索引
一个索引相当于数据库的一张表
创建索引
PUT /my_index -d '{"mappings":{}}'
字段类型
text
keyword
long
date
integer
分词器
分片
副本
删除索引
DELETE /my_index
新增字段
PUT /my_index -d '{"mappings":{}}'
查询DSL
POST /my_index/_search -d '{"query":{}}'
term
精确,针对keyword类型,text可以使用.keyword处理
match
分词匹配,针对text,搜索数据分词后匹配字段的分词数据
wildcard
模糊匹配,类似mysql的like
排序sort
分页from,to
track_total_hits
解决匹配分数total不能大于10000
bool查询
must
should
子查询
嵌套查询
聚合
架构
倒排索引
集群架构
熔断机制
监控接口
MySQL
索引(innodb)
innodb属于聚合索引
尽量使用覆盖索引、联合索引
b+树
类似b树
相较于b树:叶子节点无数据,最末节点由链表指针相连
explain
type
all(全表扫描)
index(索引扫描)
range(索引范围查询)
eq_ref(索引精准定位)
const、system(单行记录查询)
null(无数据查询)
extra
Using filesort(group by、order by使用了文件排序)
Using temporary(使用了临时表存数据)
Using index(覆盖索引)
Using where(如果使用索引,那么没有覆盖索引)
事务
事务隔离级别
读未提交(会出现脏读)
读已提交(会出现不可重复读)
可重复读(会出现幻读(针对删除))
序列化
锁
范围
表锁
GAP锁
行锁
级别
共享锁(S)
独占锁(X)
MVCC
undo日志版本链
每一个增删改都会记录到日志版本链中,按照先后顺序形成一个链表
readview一致性试图
每开始一个事务会生成当时的最大事务id、最小活跃事务id、活跃事务id集合的readview
查询时比对方式(可重复读)
1、版本链中的事务id<最小活跃事务id,
那么这个事务就是已提交事务就查询该版本数据
那么这个事务就是已提交事务就查询该版本数据
2、如果版本链中的事务id >= 最小活跃事务id
& 版本链中的事务id <= 最大活跃事务id,此时分情况而定
& 版本链中的事务id <= 最大活跃事务id,此时分情况而定
a、如果版本链中的事务id在活跃事务id集合中,那么需要继续查询
b、如果版本链中的事务id在活跃事务id集合中,那么直接取该版本
3、版本链中的事务id>最大事务id,
那么在当时当时创建readview时还没有,肯定不能要
那么在当时当时创建readview时还没有,肯定不能要
死锁
8.0特性
hash join8.0.18
json增强
EXPLAIN ANALYZE 8.0.18
系统变量支持SET PERSIST持久化
资源组
InnoDB索引增强
Redis
基础数据结构
string
hash
list
set
zset
底层数据结构
可变字符串
hash
ziplist
quicklist
双向链表
跳表
配置
持久化方式
aof
类似日志顺序写,可以配置写入日志的频率,数据丢失少
文件大,每一步操作都会记录,恢复时速度慢
# 1、no:不同步
# 2、everysec:每秒备份,推荐使用
# 3、always:每次操作都会备份,安全并且数据完整,但是慢性能差
appendfsync everysec
# 2、everysec:每秒备份,推荐使用
# 3、always:每次操作都会备份,安全并且数据完整,但是慢性能差
appendfsync everysec
rdb
快照方式恢复速度快,但是更加消耗性能
除了save 、bgsave名另外,可配置自动保存快照策略(
save 300 10 )10次请求量或300秒 做一次快照更新
save 300 10 )10次请求量或300秒 做一次快照更新
aof&rdb一起使用
淘汰策略
noeviction:当内存使用达到阈值的时候,所有引起申请内存的命令会报错。
allkeys-lru:在主键空间中,优先移除最近未使用的key。(推荐)
volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
allkeys-random:在主键空间中,随机移除某个key。
volatile-random:在设置了过期时间的键空间中,随机移除某个key。
volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
allkeys-lru:在主键空间中,优先移除最近未使用的key。(推荐)
volatile-lru:在设置了过期时间的键空间中,优先移除最近未使用的key。
allkeys-random:在主键空间中,随机移除某个key。
volatile-random:在设置了过期时间的键空间中,随机移除某个key。
volatile-ttl:在设置了过期时间的键空间中,具有更早过期时间的key优先移除。
redisson分布式锁
1、是否存在lockname 的hash,不存在,那么开始加锁
(lockname中的hash中添加field=(uuid+线程id) value=1的数据)
(lockname中的hash中添加field=(uuid+线程id) value=1的数据)
2、存在lockname 的hash那么判断hash中的field是否为(uuid+线程id)
如果是那么value+1,实现可重入锁
如果不是那么获取锁失败,并返回ttl,本地线程阻塞ttl时间,到达事件后开始抢锁,
如果是有等待时间的,超出等待时间返回false
如果是那么value+1,实现可重入锁
如果不是那么获取锁失败,并返回ttl,本地线程阻塞ttl时间,到达事件后开始抢锁,
如果是有等待时间的,超出等待时间返回false
3、上锁成功后会加入一个锁续命,达到过期时间的2/3时间点时修改redis的过期时间
集群
哨兵
cluster
raft
hash槽
扩容
lua脚本
pipeline
事务
RocketMQ
架构
broker
一台机器或一个进程代表一个broker,即一个实例
CommitLog
ConsumerQueue
nameserver
简单的注册中心
生产者
消费者
消费者数量没<该topic的ConsumerQueue时新增消费者会出现Rebalance
消费者数量>该topic的ConsumerQueue时 某些消费者会无法接受消息
对于一个topic一个消费者可以消费多个ConsumerQueue,但是ConsumerQueue只能属于一个消费者
topic
一个topic可能会有多个ConsumerQueue,这些ConsumerQueue可能分散在多个broker上
磁盘顺序写
死信队列
如果一个topic配置了死信队列,如果消费16次后还是失败,那么该消息进入死信队列
延迟队列
18个级别
消息不丢失
生产者不丢失
同步发送,等待返回SEND_OK才算成功
异步发送,可以在发送时记录数据库日志,在发送回调中修改状态
broker不丢失
同步刷盘flushDiskType = SYNC_FLUSH
slave也配置同步刷盘
master同步复制 brokerRole=SYNC_MASTER
消费者不丢失
消费队列中回复成功
消费者自己维护ConsumerQueue的offset
消息不重复
使消费接口幂等
使用唯一id判断
顺序消费
消息堆积
SpringCloud
分布式事务
TCC
try
尝试操作数据库,把数据冻结
commit
修改数据,如果失败那么一直重试,可以设置超时时间,超时后cancel
cancel
修改失败,取消冻结操作
最终一致性
使用mq实现最终一致性
Nacos
注册中心、配置中心
CP、AP
raft算法同步数据
Gateway
GlobalFilter
GatewayFilter
断言
Feign
接入Spring
代理模式走不同http访问,代理前策略模式实现singtinel、hystrix限流
单独的容器
sentinel
固定时间窗
滑动时间窗
漏桶
令牌桶
算法
查找
二分查找
排序
冒泡
快排
加密
md5
AES
RSA
分布式
proxis
raft
zab
数据结构
红黑树
链表
Hash
B,B+
最小堆
跳跃表
0 条评论
下一页