面试题
2025-02-20 16:20:49 5 举报
AI智能生成
面试宝典
作者其他创作
大纲/内容
java基础
List与数组的区别
1.List 非固定长度,数组固定长度
2.ArrayList 底层实现基于数组,不支持非引用类型
3.List 插入 删除效率低于数组,功能比数组强大
HashMap
底层数据结构?
1.jdk7 数组+链表
2.jdk8 数据+链表/红黑树 解决树不均衡问题
解决哈希冲突?
链表法,将相同的hashCode值放在链表存储
如何扩容?
当Map中的元素个数超过了数组长度*0.75开始扩容,扩容容量=原容量*2
为何负载因子0.75?
过大哈希冲突过多 导致性能问题。过小 空间浪费问题
Concurrenthashmap
如何保证线程安全
数组+链表实现的,对数组加锁处理保证线程安全,基于ReentrantLock 加锁
数组+链表/红黑树实现。头部节点加锁,锁粒度更小,是通过 CAS 或 synchronized 来实现线程安全的
get
流程
是否需要加锁
put
HashTable
基于HashMap实现,在put ,get时候加上了synchronized修饰 保证线程安全性
Hashset
本质上基于HashMap实现
TreeMap
如何实现 的?
基于红黑树实现的 Key 不能为null
对比hashMap区别
底层实现方式不同 2.TreeMap可以实现自定义排序 3.TreeMap key 不能为Null
Treeset
如何实现的
底层基于TreeMap实现的 是一个有序的Set集合
对比HashSet区别
1.底层实现不同 HashSet 基于HashMap实现的 Treeset 是基于TreeMap实现的
2.Treeset 不能添加Null 是个有序的Set 集合 而hashSet 是无序的 可以添加NuLl
设计模式
单例模式
实现方式有哪些,优缺点
1.饿汉式单例
优点:执行效率高 无锁 缺点:浪费内存
2.懒汉式单例·
优点:节省内存 缺点:非线程安全
3.双写检查懒汉式单例
优点:节省内存 线程安全 缺点:效率低下
4.容器式单例
Spring IOC
实际框架应用
IOC容器式单例
工厂模式
1.工厂模式 主要分2种 1 简单工厂 2.抽象工厂
2.简单工厂 可以通过传入简单参数动态创建对象 抽象工厂 可以动态创建复杂对象
3.Spring 中 FactoryBean 就是工厂模式的体现
原型模式
1.原型模式主要用于对象拷贝复制,对象拷贝 分为深拷贝跟浅拷贝
2.浅拷贝 拷贝的是对象的引用 深拷贝 是 生成全新对象 可以使用序列化来实现
代理模式
1.代理模式有2种 1.jdk动态代理 2 cglib代理
2.jdk 动态代理是通过反射实现的 被代理类必须要实现接口 cglib是通过编码继承类实现的,不需要实现接口
3.Spring AOP就是使用了代理模式
装饰器模式
1.装饰模式 主要是增强对象的方法
2.Spring 中BeanWrapper就是装饰器模式体现/dubbo中wrapper
观察者模式
1.观察者模式 分为2种角色 1.被观察者/主题通知 2. 观察者 常用于方法回调
2. 被观察者 维护了观察者列表,被观察者触发观察者 回调update事件
3.观察者通过register注册到观察者列表 ,同时观察者定义了回调事件逻辑
4.Spring中ApplictionListener就是观察者模式体现,applicationContext可以publishEvent 发布一个事件,ApplictionListener 通过onApplicationEvent 监听事件
5.消息通知,回调函数可以用观察者模式
策略模式
spring 中动态加载Resource
动态选择算法或者实现类时候可以应用
责任链模式
MyBatis插件Plugins应用
Netty中Pipeline
动态指定一组对象处理请求
委派模式
Mybatis Cache
Springmvc dispatchServlet
IO
什么是BIO
BIO阻塞在哪
serverSocket.accept() 服务端等待客户端链接时候是阻塞的
IO数据的读取写入必须阻塞在一个线程内等待其完成
多线程BIO有什么问题
并发量高 开辟多个线程 CPU切换消耗资源过大,如果线程池 处理线程过小无法应对高并发
什么是NIO
简叙下NIO多路复用
IO多路复用 多个IO请求注册到Seletor上 linux监控所有注册的Seletor请求,数据准备好了就返回 可读 可拷贝
poll与epoll区别?
poll是linux 轮询selector请求 支持连接数有限 同时性能也不如epoll
epoll 是注册fd事件的callBack方式 支持连接数远超poll 同时不用轮询selector
零拷贝
什么是零拷贝
不需要内核空间到用户空间的拷贝
实现方式哪有些
1.实现方式主要有2种 1.sendFile 2.mmap
2.sendFile 是用户发送指令,内核DMA拷贝到网卡,不经过用户缓冲区
3.mmap是用户缓冲区与内核缓冲区建立共享内存,用户可以操作共享内存
4.sendFile 适用用大文件 mmap 适用于小文件 有文件大小限制
5.kafka用的是sendFile零拷贝 rocketMq用的是mmap技术
Netty
拆包粘包问题产生的原因是什么?
1.拆包问题产生的原因有2个
1.写入数据>套接字缓冲区大小
2.发送的数据>tcp协议传输数据大小
2.粘包的原因有2个
1.写入数据<小于缓冲区大小
2.接收方读取操作不及时 造成缓冲区数据堆积
如何解决拆包粘包问题
采用协议解决
1.定长协议 不够补空格
FixedLengthFrameDecoder
2.特定字符分割协议
DelimiterBasedFrameDecoder/LineBasedFrameDecoder
3.变长协议
LengthFieldBasedFrameDecoder 消息头+消息体
子主题
Https
Https 如何实现数据安全的
序列化
redis
redis 数据结构有哪些?应用场景?
Redis数据结构有几种
1.String
分布式ID
缓存
分布式锁
2.Hash
子主题
3.List
4.Set
5.ZSet
redis 内存淘汰机制
1.redis 采用定期过期+惰性过期淘汰已过期的Key
2.定期过期就是 定时拉取一定数量的Key淘汰
3.惰性过期就是Get时候判断Key是否过期,过期删除
4.redis 内存淘汰策略有4中 1.Random 随机淘汰 2.LRU 最近最少使用 3 LFU 最不经常使用 4 ttl 优先淘汰最早过期的Key
5.redis 可以通过maxmemory-policy 设置淘汰策略
redis持久化策略有哪些?有什么优缺点?
1.redis 持久化策略有2种 1.rdb 文件 2.aof文件
2.rdb是redis快照文件 每隔一段时间后台线程会生成一份rdb快照 优点是不影响主操作 缺点是 丢失数据
3.aof 存储是redis操作指令,redis 每次操作命令都会存储到redis aof缓存,aof 内容定时/实时存入磁盘 默认1s一次 优点是 安全性高,可做到不丢失数据 缺点是性能低 会影响主线程操作
简叙下redis主从复制流程
1.redis 主从复制分为全量复制 和增量复制 2种情况
2.首次复制是全量复制 首先 slave 发送命令给master master接到命令 开启bg线程 生成rdb快照,同时缓冲后续请求, slave接收到rdb快照 清空数据 执行复制
3.master 将建立长连接将后续请求发送给slave slave 执行命令
4.增量复制 slave与master 断开连接时候产生,此时slave 连接master 请求带上offset,master根据offset 将后续命令同步给slave
简叙下redis 哨兵模式原理
1.redis 哨兵 是通过哨兵节点监听主节点 哨兵节点每隔一段时间会向master 发送心跳请求,如果超时 就会认为master 主观down
2.主观下线后,哨兵节点会发送命令给其他哨兵节点,其他哨兵节点会给master 发送心跳包,如果超时过半,此时master 就会被认为客观下线,哨兵节点就会发起Master 选举 ,选举算法采用的是raft算法
3.影响成为master 因素有 1.网络 断开连接时长 2.配置优先级 3.offset 最大 数据最全 4.进程ID
redis 集群算法
什么是缓存穿透?如何解决?
请求一个不存在的数据 导致跳过缓存不停的请求数据库
解决思路:通过缓存快速验证数据是否存在
布隆过滤器缓存所有数据
什么是缓存雪崩?如何解决?
大量缓存同时失效
redis 挂了
搭建集群,主从
ttltime一致
设置不同过期时间
什么是缓存击穿?如何解决?
某个时间段 缓存失效,大量并发请求
解决思路:锁
分布式锁
mq
如何保证消息的可靠性
rabbitMQ
发送消息的可靠性
1.发送事务消息
效率问题
2.ACK消息
单挑发送
效率问题
批量发送
数目问题,过大失败,过小效率
异步发送
推荐 效率高,通过异步回调实现
接收消息的可靠性
1.消息持久化
队列持久化、消息持久化和交换器持久化。
2.高可用 集群
消费消息的可靠性
消费者应答机制 默认自动应答 改成ACK手动应答
kafka
发送消息的可靠性
1.kafka 为了保证效率是通过批量发送到Page cache,异步刷盘来实现高性能
2.kafka发送消息方式有三种
1.发后即忘 无返回值发送 效率高 可靠性差
2.同步发送 Future 获取返回结果 效率低 可靠性高
3.异步发送 Callback 获取返回结果 综合性能好
3 kafka flush刷盘 策略
多少条消息刷盘1次
log.flush.interval.messages
多久刷盘一次
log.flush.interval.ms
周期性刷盘时间
log.flush.scheduler.interval.ms
接收消息的可靠性
1.kafka接收消息服务端Ack机制 分为三种
Ack=0
不需要服务端Ack 效率快 可靠性不高
Ack=1
leader落盘Ack 有丢消息风险
Ack=-1
所有Follower 全部落地Ack
重复消费消息问题
开启幂等性enable.idempotence=true
2.本地存储
配置log.dirs
文件夹:<topic_name>-<partition_id>
Segment
xx.index
索引文件
xx.log
消息
xx.timeindex
Segment
消费消息的可靠性
消费消息提交offset
同步发送
commitSync
异步发送
commitAsync
rocketMq
发送消息可靠性
同步发送
当前线程等待 broker 响应 发送结果
异步发送
线程池异步回调,返回结果
单向发送
不保证可靠性
消息重试机制
选择
同步发送+消息重试机制 保证可靠性
接收消息的可靠性
rocketMq接收到消息写入PageCache 刷盘方式有2种
同步刷盘:写入PageCache立即刷盘CommitLog 保证了可靠性,但是性能低
异步刷盘:写入PageCache 定时写入CommitLog 可靠性低 性能高
主从同步的可靠性
同步复制:主从均写入成功返回消息接受成功
异步复制:主写入成功就返回消息接收成功
消费消息的可靠性
消费消息返回CONSUME_SUCCESS 确保消息被消费
异常返回CONSUME_LATER 消息会被重试
如何保证消息的有序性
rabbitMq
单消费者单线程消费
kafka
只能保证一个partion内单线程消费的有序性
rocketMq
发送消息的有序性
全局有序
指定唯一队列发送
局部有序
相同业务流程指定同一个队列
消费消息的有序性
多线程+锁MessageListenerOrderly顺序消费
消息堆积如何处理?
解题思路
1.堆积会产生什么问题?
1.MQ服务器内存局限性,无法及时有效淘汰内存
2.MQ服务器down机导致后续大量请求失败
3.如果加快消费效率 ,让消息不再堆积
2.如何解决这些问题
1.如何淘汰有效内存·
2.淘汰内存如何处理
解决方案
1 如何淘汰有效内存
内存到达一定比例,将一部分内存中数据刷盘,然后淘汰掉
2.大并发访问MQ链接不可用怎么办
连接池技术,让后续链接排队获取连接请求
3.如何增加消费速率
1.多线程消费
2.多消费者消费
如何保证消息的幂等性,不被重复消费
生成唯一消息ID redis setnx
rabbitMQ
延迟消息如何实现
采用插件rabbitmq_delayed_message_exchange
死信队列
过期的消息ttl
消息超长
消费者拒绝reject/nack 并且requeue=false
集群模式哪几种?有什么优缺点
普通集群
不能保证高可用,数据分散分布
镜像模式
高可用,性能低
kafka
rocketMq
什么是half消息
1.发送half消息
改写Topic 头,保存原有Topic到Properties中 写入commitlog
2.执行本地事务
3.commit事务
查询half消息 改写Topic头,写入CommitLog,删除事务消息的CommitLog
4.rollback事务
删除commitLog
延迟队列的实现原理是什么?
与half消息一直 发送延迟消息 改写Topic头,定时器扫描延迟队列,改写Topic实现消息投递
死信队列的触发条件
消费失败重试达到最大重试次数后进入队列
如何存储检索数据的?
ConsumeQueue->offset->commitLog->message
主从同步流程
commitLog复制
1.定时器 slave链接master 发送拉取请求 以及自己的commitLog的offset
2.master 接收请求,与master offset比较,生成要同步commitLog buffer,发送给slave
3.slave接收到master请求,写入本地commitLog
元数据的复制
定时任务处理
JVM
JVM 运行时数据如何存放
1.JVM运行时数据区 分为 1.方法区 2 堆 3 栈 4 本地方法栈 5程序计数器
2.方法区 属于堆上一种 方法区存放类的描叙信息,常量,静态变量,方法区内存溢出会触发OOM 线程公有
3.堆 存放对象,数组 内存溢出会触发OOM 线程公有
4.栈 线程私有 生命周期跟线程一致 栈由N个栈帧组成,栈溢出会触发StackOverflowError
5.本地方法栈 java 中native 方法
6.程序计数器 线程私有的,记录线程执行位置
JVM内存结构有哪些?
JVM 内存总体分成2部分 1.老年代 2.新生代
1.新生代 又划分了三个区域 edem区 s0 s1区
2.新创建的对象会分配到新生代的edem区 新生代的GC称为youngGC
3.经过young GC 如果对象还存活 便会进入S区
4.如果young 区分配不下的对象或者young gc 15次以上还没有被回收的对象 会进入Old区
5.old区达到一定比例会触发Full GC
6.old区也放不下的对象 会触发OOM
如何确定对象为垃圾
JVM 通过GCRoot引用不可达判断垃圾
可以作为GCRoot对象 有 线程,类加载器 ,栈中变量,本地方法栈的变量 ,常量,static成员
JVM垃圾回收算法有哪些?特点是什么?
1.JVM 垃圾回收算法有3种 1.标记清除 2 复制 3 标记整理
2.标记清除算法有内存空间不连续问题
3.复制算法有空间浪费问题
4.标记整理有效率低下问题
Jvm垃圾回收器有哪些?
1.垃圾回收器主要有5种 1Serial 2 ParNew 3.Parallel4.CMS 5.G1
JVM各个垃圾回收器特点以及使用场景
1.Serial 是单线程垃圾收集器 他有适用于新生代和老年代版本 新生代采用的是复制算法 老年代Serial Old 采用的是 标记整理算法,
2.ParNew与Parallel 是多线程垃圾收集器 Parallel更加关注吞吐量 新生代版本采用复制算法 老年代采用标记整理算法
3.CMS 适用于old区垃圾收集器 采用标记清除算法,关注停顿时间,适用于后端任务的垃圾处理器
4.G1 适用于新老年代垃圾收集器 采用标记整理算法 可以自设置停顿时间 适用于web交互场景
CMS垃圾收集器流程
CMS垃圾收集器垃圾回收可分4步
1.初始标记
对GCRoot能直接关联的对象打标 会STW 速度快
2.并发标记
对关联对象开始遍历整个对象图,多线程处理 不会终止用户线程
3.重新标记
修正用户线程产生变化的标记 会STW
4.并发处理
多线程 处理垃圾回收 不会终止用户线程
G1垃圾收集器流程
G1垃圾收集器可以分4步
1.初始标记
标记GCROOT直接关联的对象
2.并发标记(不会终止用户线程)
3.最终标记
4.筛选回收(有选择性回收垃圾,重复回收)
Jvm调优常用命令有哪些?作用是什么?
JVM 常用调优明细有 jps jinfo jstat jstack jmap jhat
jps 查询java 进程信息 获取进程ID
jinfo 查询JVM参数 堆内存大小 垃圾收集器
jstat 查看jvm运行时状态信息, 包括内存状态、垃圾回收
jstack 查看jvm线程快照的命令
jmap 生成dump文件,查询堆内对象示例的统计信息、查看classLoader的信息以及finalizer队列
jhat 分析dump文件 用于离线分析
常用堆分析工具有jvisualvm mat arthas
常用 GC log分析工具有GCViewer gceasy.io
Full GC频繁如何解决
分析FULL GC可能产生的原因
1.方法区FullGC
方法区太小?
类加载太多?
2.堆上FullGC
大对象?
内存泄漏未回收?
空间碎片问题?
高并发问题?
程序效率问题?对象长时间得不到释放?
堆过小问题?
解决问题
1.jstat 打印gc日志,查询内存空间大小
2.jmap 查询内存使用情况
3.jstack 查询线程,cpu请求情况
4.dump堆文件,mat工具分析
5.高并发问题?增大S区
6.空间碎片问题?切换垃圾收集器
GC频繁如何解决
分析原因
1.堆内存空间不足
2.edm区域太小,频繁ygc 大量对象进入old区
3.代码问题 大对象
解决问题
1.jstat 打印gc日志,查询内存空间大小
2.minor gc/major gc 工具gceasy查看
3.jmap 查询内存使用情况
OOM如何排查问题
分析原因
方法区/堆上OOM?
方法区OOM 原因?
动态生成类 加载类?
cglib
方法区分配太小?
堆上OOM原因?
死循环添加对象?
程序慢 大对象不能释放?
内存太小?
高并发?瞬时大量请求 创建大量对象?
内存泄漏?
解决问题
1.确定是堆上OOM还是方法区/元空间上OOM
2.方法区OOM java.lang.OutOfMemoryError: MetaSpace
增大元空间大小,配置参数-XX:MaxMetaspaceSize=xx
3.堆上OOM OutOfMemoryError: Java heap space
jmap dump 堆上内存信息。mat 分析有没有大对象
4.jinfo 查询堆内存大小,比例情况。元空间大小。垃圾收集器的选择。
5.查询线程cpu 使用情况,看看是否高并发,增加集群机器
CPU飙升如何解决
分析原因
1.高并发 访问过多?
2.多线程 死锁?
3.消耗CPU的计算任务?
4.FullGC过多?
解决问题
1.查明哪个进程导致CPU飙升
1.top查询cpu使用率高的应用ID
2.jstack 查询线程使用情况,排除死锁问题
3.jinfo 查询JVM参数信息,jmap查询堆内存使用情况
4.jstat 统计FullGC情况
分布式
分布式ID生成有哪些
子主题
分布式事务解决方案
强一致性
XA协议
需要数据库支持
性能差
弱一致性
TCC
try confirm cancel 补偿型事务·
Seata
支持 AT TCC SEAGA XA4种模式
选举算法有哪些
子主题
限流算法有哪些
计数器
临界值问题
滑动窗口
缩小范围
漏桶算法
无法应对瞬时高并发场景
令牌桶算法
解决高并发场景
一致性哈希算法原理?如何解决数据倾斜问题?
布隆过滤器原理?
使用一组哈希函数,将元素映射成一组位数组中的索引位置
秒杀如何设计?
分析问题
秒杀特点
1.高并发
2.读多写少
3.无效请求多
秒杀问题
1.流量过大导致服务端挂掉
2.数据库链接问题
3.缓存问题
4.库存问题
5.消息丢失
6.限流
设计思路
1.减少静态资源占带宽IO资源
动静分离
客户端缓存静态资源
2.数据库读问题
redis缓存信息
缓存击穿
分布式锁
缓存穿透
布隆过滤器
3.库存问题
数据库扣减库存
1.加锁性能问题
2.不加锁,读取与更新非原子性 造成库存超卖
3.乐观锁高并发带来死锁问题
redis扣减库存
2.lua 脚本扣减库存
发送下单Mq
1.生成订单
2.发送延迟消息 回查订单是否扣费
限流控制
1.IP限流
存在伪造IP可能
2.验证码
大文件导入导出如何设计?
缓存一致性如何解决?
子主题
子主题
中间件
dubbo
dubbo 支持哪些协议?各个协议使用场景
dubbo协议(默认)
变长协议,适用于高并发 小数据传输,消费者比提供者个数多
hession协议
传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可传文件
thrift协议
grpc协议
rest协议·
rmi协议
http协议
webService协议
memcached 协议
dubbo 支持哪些序列化方式?使用场景?
dubbo 配置优先级
⽅法级优先,接⼝级次之,全局配置再次之
如果级别⼀样,则消费⽅优先,提供⽅次之
dubbo SPI
接口添加@SPI注解,配置文件需放置在 META-INF/dubbo,通过键值对的方式进行配置
扩展点ExtensionLoader
getExtension
根据名称扩展
getAdaptiveExtension
根据url参数动态扩展
getActivateExtension
根据条件扩展
dubbo 注册流程
zk
es
es为什么查询快
1.倒排索引设计 ,通过各种压缩算法,缓存算法将索引存在内存 从而实现内存索引查找
子主题
es用的是悲观锁还是乐观锁?如何实现的?
乐观锁
if_seq_no(自增号)+if_primary_term(分片号) 实现乐观锁
version 主分片写入成功,备份分片还未同步,主分片down机会有问题,版本号还未+1
es 脑裂问题的原因是什么?如何发现?如何解决?
原因
master 性能问题导致超时重新选举master
如何发现
解题思路
避免超时
Master与Data节点不能为同一个,否则容易导致负载过高
增加主节点的响应时间discovery.zen.ping_timeout 默认是3s
es 路由算法
shard = hash(routing)%分片数
es 为什么是近实时的?说说存储流程?
写入数据->memory buffer(不可查询)->refresh File system cache(1s 可查询)->flush 磁盘(30m)
事务日志translog->commit point 记录最后刷盘位置->异常恢复数据
多线程
线程状态
线程有几种状态?
1.线程有7种状态 分别是NEW,READY,RUNNING,WAITING,TIME_WAITING,BLOCKED,TERMINATED
2.NEW是初始化状态,实例化线程时候产生的状态new Thread
3.READY是就绪状态,线程调用start方法时候等待CPU调用产生
4.RUNNING是运行状态,CPU调度运行状态
4.WAITING是等待状态,TIME_WAITING是超时等待,等待某个线程的特定操作才会被唤醒
5.BLOCKED是阻塞状态,只有 Synchronized 同步锁等待才会存在这个状态
6.TERMINATED是终止状态
各种状态之间如何切换?
1.实例化线程NEW状态->等待CPU调用READY状态->Synchronized抢锁 失败BLOCKED状态->抢锁成功RUNNING状态->主动/被动执行结束TERMINATED状态
Thread.yeild(),notify(),unpark() 可以使线程进入READY状态
Thread.join(),wait(),park() 可以使的线程进入Waiting状态
如何终止一个线程
Thread.stop 强制终止线程,会使执行中断,不推荐
Thread.currentThread.isInterupted(),推荐使用,发送信号终止执行
锁
synchronized
实现原理是什么?
1.synchronized是java 关键字实现对 对象/方法上加锁
2.底层是由JMM自己实现的
3.底层是对Object对象头上 存储字段锁标记位进行修改来实现,由MonitorEnter 加锁/MonitorExit 释放锁实现
Lock
实现原理是什么?
如何抢锁?
1.Lock 底层是由AQS实现,抢锁是通过CAS修改共享变量state实现
抢锁失败如何处理?
2.未抢占到锁线程,通过park()方法挂起线程,挂起的线程会存储到AQS的双向链表队列等待被唤醒
如何唤醒等待线程?
3.RUNING线程执行结束 会调用unlock方法 unlock会通过unpark()方法会将链表中线程唤醒
公平锁与非公平锁区别?
非公平锁会在CAS失败后 再执行一次tryAcquire抢锁操作
ReadWriteLock作用
写写互斥/读写互斥/读读不互斥 能够实现并发读
Condition
condition有什么作用?
await
阻塞当前线程 保存到Condition队列
释放AQS锁
signal
将condition队列 第一个线程移动到AQS队列
唤醒condition队列中的线程
简叙下condition的实现原理?
AQS中维护着一个Condition单向链表
await方法阻塞当前线程,存储到Condition队列,并唤醒处于阻塞状态下AQS线程
signal
将condition队列移动到AQS队列,并且唤醒线程
AQS
简叙下AQS流程
AQS中内部维护了一个volatile int state=0 状态为和一个FIFO的队列
state 抢占锁 通过CAS操作改成 1,后续线程抢锁失败会保存到FIFO的队列,通过locksupport.pack()挂起当前线程
线程执行结束 通过CAS操作修改state=0 同时 通过locksupport.unpack()唤醒FIFO队列里面的线程继续操作。
state 抢占锁 通过CAS操作改成 1,后续线程抢锁失败会保存到FIFO的队列,通过locksupport.pack()挂起当前线程
线程执行结束 通过CAS操作修改state=0 同时 通过locksupport.unpack()唤醒FIFO队列里面的线程继续操作。
关键字
ThreadLocal
ThreadLocal实现原理是什么
1.ThreadLocal 采用空间换时间,每一个线程对象里面都有一个ThreadLocalMap,ThreadLocalMap存储的是ThreadLocal本身,以及其对应设的值
ThreadLocal存在什么问题?如何解决?
内存泄漏,因为弱引用关系,要通过调用ThreadLocal.remove 删除弱引用
ThreadLocal如何解决哈希冲突的
寻址法解决哈希冲突问题,即哈希到位置 不为空 则寻找下一个位置插入
volatile
volatile有什么作用
保证可见性
保证有序性
线程组件
Countdownlatch
Countdownlatch使用场景是什么
多任务并行处理 主任务等待处理结果
CountDownLatch如何实现的
AQS 初始化 state=N 通过countDown 减1,直到state=0 退出循环 唤醒AQS队列主线程
通过await 挂起当前线程,并且加入到AQS队列
Semaphore
Semaphore使用场景是什么
限流:定义同时只能有N个线程同时访问,类似限流,其他线程等待线程执行完成
子主题
Semaphore如何实现的
1.AQS初始化state=N,
2.acquire 获得令牌 state-1 失败加入AQS队列
3.release 释放令牌 state+1 唤醒AQS队列中线程
CyclicBarrier
CyclicBarrier使用场景是什么
生产者 消费者模型 可循环使用的屏障
CyclicBarrier如何实现的
await
condition.await
到达指定N个线程 condition.signalAll
reset 重新初始化
初始化
state=n
CyclicBarrier与CountDownLatch有什么区别
1.CyclicBarrier基于Lock+condition实现的,CountDownLatch继承AQS实现的
2.CyclicBarrier可以重复使用;而CountDownLatch是一次性的,不可重复使用
3.CyclicBarrier中操作计数和阻塞的是同一个线程,调用方法只有一个await方法;而CountDownLatch中操作计数和阻塞等待是N个线程,控制计数调用方法countDown
CompletableFuture
CompletableFuture有何作用,与Future区别是什么
功能:异步执行、链式操作、任务编排 默认线程池ForkJoinPool.commonPool()
Future
Future如何实现的
get
未完成<=COMPLETING
addWait:保存当前线程到waitNode 单项链表
park:挂起当前线程
已完成
report
run
result=Callable.call()
调用callable.call方法执行线程获取返回结果
outcome=set(result)
CAS操作 将返回结果赋值共享变量
finishCompletion:遍历waiters链表 unpark 唤醒线程
ThreadPoolExecutor
线程池有几种
newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务
newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行
线程池各个参数代表含义
corePoolSize(核心线程数)
maximumPoolSize(最大线程数)
workQueue(任务队列)
keepAliveTime(线程存活时间)
threadFactory(线程工厂)
rejectedExecutionHandler(拒绝策略)
阻塞队列有哪几种
线程池设计原理是什么
execute提交执行任务
corePoolSize未满
addWork(**,true)创建线程
runWork执行线程
corePoolSize已满
workQueue队列已满
线程池已满
执行rejectedExecutionHandler拒绝策略
线程池未满
addWork(**,false)创建线程
runWork执行线程
workQueue队列未满
任务work存储队列
ForkJoin
ForkJoin使用场景
任务拆分窃取
ForkJoin可以初始化几种Task任务
RecursiveAction
无返回结果的ForkJoinTask
RecursiveTask
有返回结果的ForkJoinTask
ForkJoin中fork/join的作用
fork
向当前任务所运行的线程池中提交任务
join
获取任务的执行结果。阻塞当前线程直到对应的子任务完成
阻塞队列BlockingQueue
死锁
什么是死锁
多线程之间 互相竞争对象资源,互相等待对方资源的释放造成一直死循环等待的现象
什么是可重入锁/不可重入锁
可重入锁,是指获得当前锁的线程,再次获得当前锁资源时候不需要获得锁
死锁怎么解决
2. 锁顺序一致性 例如 线程A,B均是锁Obj1 然后锁Obj2
3. 使用定时锁,设置timeout 锁自动失效
1.增大锁范围 全局锁
CAS
什么是CAS
内存比较修改法,如果内存地址V的值=A,则修改成B,否则失败
CAS缺陷
1.ABA问题,将A改成B再改成A 此时 无法判断内存里面值是否被修改
2.自旋CAS,如果一直不成功,一直循环处理,加大CPU负担
3.只能修改一个变量值
子主题
mysql
mysql 存储引擎有哪些?有什么特点
1.Mysql存储引擎有innoDb(默认),MyIsam,CSV,Memory,CSV几种
2.innoDb是Mysql默认存储引擎,支持事务ACID,行锁,MVVC综合性能较好,索引跟数据存储在一个文件里面
3.MyIsam 不支持事务,表锁,读写性能高,更新删除性能差,适合做报表展示类 ,索引跟数据单独存储
4.Memory 数据存放内存,读写性能最高,数据不安全,重启崩溃都会丢失数据,适合做临时表,支持哈希索引
5.CSV 数据存放CSV文件 不支持索引 适合数据导入类场景
innoDb与MyIsam的区别
innoDb: 支持事务 行锁 MVVC 综合性能高 索引跟数据存储在同一个文件 适合做业务表
MyIsam: 不支持事务 表锁 读写性能高 更新删除效率低 索引跟数据单独存储 适合做报表查询
innoDb采取什么结构作为索引?他的优势劣势?
innoDb采用B+tree做索引
BTree和B+Tree 对比与AVL树,他解决了AVL 每个Page存储数据量太少,IO次数过多的问题
B+Tree对比于BTree 因为B+Tree的特性是叶子节点存储数据,非叶子节点存储索引。所以B+Tree 建立索引空间占用更小
B+Tree 因为叶子节点数据是排序且连续的,所以对于排序查询效率比较好,而BTree 由于非叶子节点也存储数据,所以直接查询效率会比B+Tree高
innoDb的哈希索引有什么优势?使用场景是什么
哈希索引查询效率高 因为是KV结构
哈希索引不支持条件,范围查询
只有Memory引擎建立的表才支持hash索引
如何优化索引
innoDb如何保证数据的可靠性
innoDb通过双写BufferPool与log_buffer保证数据的可靠性
log_buffer默认通过定时任务1s 写入本地磁盘,因为是顺序IO 所以效率高
理论上还是会丢失数据 可以设置刷盘策略innodb_flush_log_at_trx_commit 提交刷盘保证可靠性
innoDb如何保证原子性,undolog什么时候写入的
1.innoDb通过undo_log保证原子性,undo_log记录更新之前的数据
2.undo_log 提交事务之前写入
innoDb中buff_pool作用是什么
1.读写内存提高innoDb的读写效率
2.通过异步刷脏来保证数据的可靠性
innoDb内存如何淘汰
1.innoDb 采用LRU 最近至少使用算法淘汰内存
2.innoDb对LRU算法做了改进,防止访问大量冷门数据造成热数据缓存失效
3.innoDb改进后的LRU算法 将BuffPool中数据按照5:3比例分成young区 old区
4.访问不存在的数据会放到Old区,按照策略选择移动到Young区或者保留在Old区
5.Old区在链表尾部,被淘汰优先级别较高
简叙一条select语句执行过程
1.先从Buffer_pool里面加载数据
2.buff_pool 查找到记录 直接返回
3.buff_pool 未查找到记录,从磁盘中加载 数据到buff_pool 然后返回数据
简叙一条update语句执行过程
1.加载数据,执行select 操作
2.更新server执行器数据
3.记录undo_log 更新前数据
4.记录redo_log更新后数据
5.更新buffer_pool数据
6.server执行器记录bin_log
7.提交事务,异步刷脏
innoDb事务隔离级别有哪些
1.innoDb事务隔离级别有4中 1.RU 未提交读 2.RC 已提交读 3.RR 可重复读 4.SZ串行化
2.RU 级别未解决任何问题 存在脏读,幻读 ,不可重复读 问题
3. RC 已提交读 解决了脏读 ,未解决幻读,不可重复读问题
4.RR 解决不可重复读问题 innoDb通过行锁解决了幻读问题
5.SZ串行化解决了所有问题
事务隔离级别RR与RC区别是什么
1.RR解决了不可重复问题 RC未解决不可重复读问题
2.RR是加行锁 RC未加行锁 所以RC效率更高
3.RR 通过记录第一次查询的ReadView保证不可重复读问题,而RC每次查询都是一个新的ReadView
innoDb MVVC实现原理是什么
1.innoDb mvvc实现原理是undo_log多版本快照读实现的
2.每次增删改 都会产生新的的View 每个View上保存了行ID,事务ID,回滚指针
innoDb 行锁算法有哪些?
1.innoDb RR模式下行锁算法有3中 分别是记录锁 间隙锁 临间锁
2.记录锁--触发条件 主键查询并且命中记录
3.间隙锁--触发条件 主键查询并且未命中记录
4. 临间锁--触发条件 范围查询 ( ] 左开右闭
如何定位慢sql,如何优化慢sql
1.定位慢sql 可以修改配置文件(/etc/my.cnf),mysql开启慢sql监控
2.慢sql 可通过执行计划排除未走索引字段
死锁问题原因?如何解决死锁问题
多个事务之前相互争抢资源,锁定资源相互等待造成死锁
解决死锁从以下几个方面考虑
1.顺序访问,排序,锁定资源顺序一致
2.申请全局锁,扩大锁范围
3.事务拆分,避免大事务
4.避免条件范围过大
子主题
spring
IOC
简叙下Spring IOC初始化流程
1.初始化Environment
2.加载解析XML,生成BeanDefintions
3.缓存BeanDefintions
4.初始化BeanFactory
BeanFactory与FactoryBean区别是什么
BeanFactory 是IOC容器接口,FactoryBean是创建Bean接口
DI
简叙下Spring DI流程
1.doGetBean开始
2.缓存是否存在Bean 缓存中获取Bean
3.不存在 创建Bean 加入缓存factoryBeanObjectCach
Spring 如何解决循环依赖问题
三级缓存
一级缓存完整的Bean对象
二级缓存未创建完成的Bean
三级缓存beanFactory.getObject()
AOP
Spring 中采取何种方式实现AOP
如果类实现了接口默认采用JDK动态代理实现
如果类未实现接口则采用CGLIB实现AOP
CGLib与JDK动态代理区别是什么
CGLIB 实现方式是通过编写字节码继承实现
JDK是通过反射调用接口实现
Spring为什么默认采用JDK
CGLIB代理是需要JVM动态加载类信息的,如果滥用容易造成OOM
MVC
简叙下Spring Mvc流程
1.初始化DispatchServlet
1.初始化HandlerMapping
2.初始化HandlerAdapter
3.初始化ViewReslovers
2.运行阶段
1.http请求->拦截->dispatchServlet
2.HandlerMapping->匹配->Controller与拦截器(HandlerExecutionChain)
3.HandlerAdapter->执行->Controller方法->生成->ModelAndView
4.ViewResolver->解析->ModelAndView->生成->View->HttpResponse
Spring Boot
简叙下Spring boot自动装配原理
@SpringBootConfiguration
@EnableAutoConfiguration
@Import
AutoConfigurationImportSelector
SpringFactoriesLoader.loadFactoryNames
Spring boot中如何实现配置加载的
spring cloud
Ribbon
Ribbon作用是什么?
在代码上添加@LoadBalanced注解 可以实现负载均衡远程调用
如何自定义负载均衡策略?
1.自定义类继承AbstractLoadBalancerRule 重写choose方法
2.配置文件指定负载均衡策略NFLoadBalancerRuleClassName
Ribbon 的负载均衡是如何实现的?
1.Spring Cloud 里面定义@LoadBalanced注解 本质上是个@Qualifier注解
2.Spring Cloud里面LoadBalancerAutoConfiguration自定装配类会扫描加载所有加了@LoadBalanced注解的RestTemplate
3.给这些RestTemplate添加了一个拦截器LoadBalancerInterceptor,这个拦截器使用LoadBalancerClient 执行http请求
4.RibbonAutoConfiguration 会初始化LoadBalancerClient实现类RibbonLoadBalancerClient
5.RibbonLoadBalancerClient 定义了负载均衡算法
Eureka
什么是Eureka的自我保护机制
在一定时间内超过一定比例的客户端心跳请求失败 Eureka进入自我保护机制
自我保护机制下 Eureka 不会剔除过期服务,可以接收新增和查询请求 但是不会同步到其他节点
Eureka的自我保护机制是AP还是CP模型
AP模式
OpenFeign
OpenFeign有什么作用
OpenFeign 声明式伪RPC的Rest接口,可以向调用RPC一样调用Rest接口
OpenFeign实现原理?
1.OpenFeign通过@FeignClient 定义一个Feign接口对象
2.Spring Cloud 初始化@EnableFeignClients 通过实现ImportBeanDefinitionRegistrar导入Bean到IOC容器
3.ImportBeanDefinitionRegistrar 会扫描@FeignClient 类 通过FactoryBean动态生成一个AOP代理对象加载到IOC容器
4.这个代理对象 实现了远程调用功能
Hystrix
Hystrix有什么作用
Hystrix 可以实现服务 熔断、降级策略 有效防止系统崩盘
Hystrix 熔断的隔离机制有几种?优缺点?
Hystrix 熔断的隔离有2中 1.信号量隔离 2.线程池隔离
1.信号量是记录多少时间内有多少个请求,计数器实现
2.线程池是记录并发线程处理多少请求 默认是采用线程池隔离
3.信号量隔离 同步单线程调用 支持熔断 不支持超时 会一直阻塞
4.线程池隔离 多线程支持异步调用 支持熔断 支持超时解除阻塞 多线程会造成CPU负载高
Hystrix 熔断算法是什么
Hystrix 熔断算法 是基于滑动窗口算法实现的
Hystrix如何实现服务降级?有几种方式?
Hystrix 同注解@HystrixCommand定义服务降级,可以实现某个方法服务降级,可以自定义全局服务降级逻辑
Gateway
Gateway有什么作用,使用场景是什么
Gateway 可以拦截过滤请求,可以实现鉴权,限流,日志,缓存等功能
GateWay三大核心概念是什么?分别作用
GateWay三大核心概念 有 路由 断言 过滤器
路由定义转发的路径 路由包含了断言 过滤器
断言 相当于条件判断逻辑 匹配上则执行路由逻辑
过滤器 分为两种 1全局过滤器 2网关过滤器 可以修改或者增强http请求
Nacos
Nacos有什么作用?
Nacos 可以做动态配置中心与注册中心
Nacos如何实现配置自动刷新
NacosConfigService 初始化会启动一个线程 检查本地缓存MD5与服务MD5是否一致
不一致请求最新配置,保存到cachData
cachData发布一个Event ,这个Event 会刷新Environment 将最新配置加载到Environment中实现类自动刷新
Sentinel
Sentinel有什么作用
与hystrix一致
Sentinel如何实现动态规则
集成Nacos
Seata
Seata有什么作用
seata提供了微服务框架下 分布式事务解决方案
Seata提供了几种事务模式?以及各个事务模式优缺点
seata 提供了4种事务模式 1.XA事务 2.AT事务 默认 3.TCC事务 4.SEAGA
1.XA事务 强一致性 需要数据库支持XA协议 性能不稳定
2.AT 事务 弱一致性 有脏读问题,性能较好,基于BIN_LOG补偿性事务
3.TCC 事务 弱一致性 需要写 try confirm cancel 三个接口,代码冗余,性能较高,存在幂等,空回滚,悬挂等问题 可以通过本地事务表记录XID判断解决这些问题
幂等问题
重复调用Confirm/Cancel方法
思路:执行方法check事务日志表status,校验Confirm/Cancel是否已执行
悬挂问题
RPC调用超时,try请求未执行就调用了Cancel,之后请求真正到达try
Cancel记录到事务日志表中,try 判断是否已经Cancel,已经cancel直接退出
空回滚
try未执行/执行异常 调用了Cancel方法
思路:try方法记录xid,事务ID,Cancel方法判断try是否正常执行
4.SAGA模式 最终一致性 依据调用链路依次补偿,恢复模式有2种 1.向前恢复 重试保证成功 2.向后恢复 补偿失败请求 性能高 代码冗余
子主题
AT模式下脏写,脏读问题如何解决
脏写问题
通过@GlobalTransactional 串行化保证写隔离
通过@GlobalLock+select for update 保证写隔离
脏读问题
默认未解决,可以通过select for upate 解决
Seata存储模式有哪些?优缺点是什么
seata 数据可以存在 Db,本地文件,redis中
1.存储在DB中 可靠性高 不会丢失数据,需要初始化表,性能有一定瓶颈
2.存储在文件 可靠性差,部署简单,性能好
3.存储在Redis 性能高 存在丢失数据风险 因为redis 数据存储在内存,定时任务备份Rdb
Seata AT模式执行流程
1.TM向TC申请全局事务,TC 创建全局事务
2.TC将全局事务XID返回给TM,RM注册分支事务到TC,并且绑定XID
3.执行分支事务,记录undolog,执行结构反馈给TC
4.TC 提交/回滚命令RM RM提交/回滚事务
DevOps
git
jenkens
docker
k8s
0 条评论
下一页