面试题汇总
2024-04-18 11:41:27 3 举报
AI智能生成
登录查看完整内容
java面试题
作者其他创作
大纲/内容
发生的条件:查询一个不存在的数据,MySQL查询不到数据也不会直接写入缓存,导致每次查询都会请求到数据库
优点是简单
数据丢失,容易造成不一致问题
缓存空数据,将查询的数据设置为空,仍把这个空结果进行缓存
优点:占用内存较少,没有多余的key
缺点是:实现起来比较复杂
使用:在缓存预热的时候往布隆过滤器里添加数据,会直接查询布隆过滤器
布隆过滤器使用Redission来实现布隆过滤器:底层是初始化一个比较大的数组里面存放0或者1,放置一个key进行3次的hash计算,通过去模的方式将数组下标把原来的数组改成1。这样的话3个数组位置就能标明一个key存在
布隆过滤器也是有一定的缺点的,容易造成误判。我们可以设置误判率,误判率百分之5以内不至于在高并发下面压倒数据库
布隆过滤器:布隆过滤器通过bitmap位图来检索一个元素是否在一个集合中。作用是拦截不存在的数据
如何解决缓存穿透
什么是缓存穿透,怎么解决
发生的条件:给某一个key设置了过期时间,当这个key过期的时候恰好有大量的并发请求打在了这个key上
高可用性
高可用,性能优
热点key不过期
互斥锁的流程:线程一查询缓存未命中,这个线程会获取互斥锁,之后去查询数据库重建缓存数据,再将数据写入缓存中,最后释放锁。线程2查询缓存未命中时,因为互斥锁的缘故它会休眠一会重试直到线程一释放锁
强一致性,性能差
设置互斥锁
如何解决缓存击穿
什么是缓存击穿,怎么解决
发生的条件:缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
解决方案:设置不同的过期时间解决方案:如果是服务器宕机问题会使用Redis集群提高服务可用性(哨兵模式,集群模式)解决方案:给缓存业务添加降级限流策略(nginx,springcloud gateway)解决方案:给业务设置多级缓存(Guava或Caffeine)
面试回答:设置缓存时使用了相同的过期时间,导致缓存在某一时刻同时失效导致大量的数据转发到DB,与缓存击穿的区别是缓存雪崩是大量的Key,缓存击穿是某一个key缓存解决方案是将:缓存失效时间分散开在原有的基础上增加一个随机值比如1-5分钟随机
什么是缓存雪崩,怎么解决
缓存穿透,缓存击穿,缓存雪崩
可以使用限流来保底
RDB概念:将内存中的所有数据记录到磁盘中,当Redis故障重启之后从磁盘中读取快照文件,恢复数据
RDB执行原理:bgsave开始会fork主进程得到子进程,子进程共享主进程的数据,完成fork后会读取内存数据并写入RDB文件fork采用的是copy-on-write方式,写操作的时候会写数据的复制层之后去读复制层
RDB
AOF执行原理:记录每一次执行的命令,数据完整性和文件大小相对较大,宕机恢复速度慢,安全性比较高
AOF
Redis数据的持久化策略有哪些
两种持久化有什么区别? RDB是一个快照文件它把Redis内存存储的数据写到硬盘上, 当Redis实行宕机恢复数据的时候会从文件执行命令恢复数据 AOF是追加文件,Redis执行写操作时都会存储到这里, 当Reids执行宕机恢复数据时,会从文件中再次执行命令恢复数据
哪种恢复速度比较快? RDB因为是二进制文件,存储的数据比较小恢复速度比较快,但是容易造成数据丢失现象 我们通常项目中会使用AOF开恢复数据,虽然AOF恢复数据较慢一些但是不容易丢失数据 AOF中设置刷盘策略,也就是每秒批量写入一次命令
面试官问法:
1.使用MQ消息中间键,更新数据之后通知缓存删除
2.利用Canal不需要修改业务代码,伪装成mysql的一个从节点通过读取binlog来数据更新缓存
介绍自己简历上的业务,我们当时是把文章的热点数据存入到了缓存中,虽然是热点数据,但是实时要求性并没有那么高,所以,我们当时采用的是异步的方案同步的数据
为了保证强一致性采用Redission读写锁 1.共享锁:共享锁:读锁readLock,加锁之后,其他线程可以共享读操作 2.排他锁:排他锁使用的也是setnx独占锁writeLock也叫,加锁之后,阻塞其他线程读写操作
我们当时是把抢券的库存存入到了缓存中,这个需要实时的进行数据同步,为了保证数据的强一致,我们当时采用的是redisson提供的读写锁来保证数据的同步
面试回答:Redis作为缓存如何与Mysql数据库进行同步呢?(双写一致性):修改了数据库的数据也要更新缓存的数据缓存和数据库保持一致
加分布式锁
强一致性使用读写锁但是性能低
因为缓存中的数据是读多写少所以可以使用读写锁
双写一致性如何保证强一致性?(一致性要求高的)
异步通知:rabbitmq,rocketmq,kafka
Canal
最终一致性
双写一致性:读操作:缓存命中直接返回,缓存未命中读取mysql中的数据之后写入缓存设置过期时间写操作: 延迟双删:先删除缓存再删除数据库因为线程是切换的所以容易造成脏数据问题 为什么要双删? 降低脏数据的出现 为什么要延迟? 数据库是主从模式,读写分离的所以要延迟一会
延迟双删的缺点是:延迟双删先删除缓存中的数据,之后更新数据库,再之后删除缓存中的 数据 但是不好设置延迟时间而且也存在脏读问题
Redis双写问题
双写一致性,持久化
优点:对CPU友好,不用浪费时间进行检查
缺点:如果不去访问这个Key那么Key会用不释放
设置Key过期时间后不去管它,等到再次访问时判断是否过期并删除
惰性删除
每隔一段时间会定期对Key进行检查,并删除
SLOW模式是定时任务,每秒执行十次(可以手动配置)清理耗时不超过25ms'
SLOW模式
Fast模式执行的频率不固定,两次间隔不低于2ms,每次耗时不超过1ms
Fast模式
定期删除
优点:有效释放过期Key占用的内存。缺点:难以确定删除
Redis数据过期策略有哪些
面试官问法
通常是惰性删除和定期删除一起使用
noeviction:默认策略不淘汰任何Key但是内存满了不允许写入新的数据
volatile-TTL:对于设置TTL的key,比较剩余的过期时间,TTL越小的越被淘汰
Random:随机淘汰
volatile-Random:随机删除设置TTL的key
LRU-根据LRU算法进行淘汰(最近最少使用)Least-Recently-Used:优先建议使用
volatile-LRU:对于设置了TTL的key使用LRU算法进行淘汰
LFU:根据LFU算法进行淘汰(最少频率使用)Least-Frequently-Used
volatile-LFU:对于设置TTL的key使用LFU算法进行淘汰
假如缓存过多,内存被占满了怎么办?
Redis淘汰策略有哪些
使用LRU算法最近最少使用的数据来保证数据都是热点数据
数据库中有1000万条数据,Redis只能缓存20万条数据,如何保证Redis数据都是热点数据
默认情况下会直接报错
Redis内存用完了会发生什么?
数据过期,淘汰策略
缓存
Redis实现分布式锁——可重入Field是持有锁线程的唯一标识value当前线程重入次数总体的实现流程是:如果使用了同一把锁那么value值+1,如果释放了锁那么value-1
Redis实现分布式锁——主从数据一致红锁(Red Lock)不在一个Redis实例中创建锁,而在多个Redis实例中创建锁实现复杂 性能差 运维繁琐
Redis分布式锁主要是运用了setnx命令,setnx是Set if not exist的简写
分布式锁如何实现
根据业务的执行时间预估
加锁,和设置过期时间都是基于lua脚本完成(lua调用Redis命令,来保证多条命令执行的原子性)
看门狗技术假如while循环的好处是:高并发下增加分布式锁的实用性
给锁续期
Redis分布式锁如何合理的控制有效时常
分布式锁通常情况下的使用场景:集群情况下的定时,抢单,幂等性场景
注意:为什么synchoinezd锁不适合抢卷场景? 因为synchoinzed锁是本地锁,只能解决同一个线程下不能解决集群
setnx,redission
并发控制:在用户对某个数据进行更新时,可以先获取分布式锁,确保只有一个用户能够修改数据
根据简历的业务来描述分布式锁的实现场景
使用Redission分布式锁来实现的,底层原理是Setnx和Lua(来保证原子性)
Redis分布式锁是如何实现的?
使用WatchDog看门狗技术,当一个锁获取线程成功之后WatchDog会默认每十秒一次给锁续期
Redis分布式锁如何合理的控制锁时长?
可以重入:逻辑上Hash结构来存储线程信息和重入次数
Redis锁可以重入吗?
不能解决,可以使用Redis提供的红锁但是性能太低了,如果强行使用主从一致可以使用Zookeeper
Redis可以解决主从数据一致性问题吗?
面试官问题:
分布式锁
incr和decr来进行增加和减少数值指令
计数器
String字符串来保存键值对,使用expire来设置过期时间
保存token
list来实现简单的消息队列
消息队列
使用sortset来实现延迟队列
延迟队列
使用场景
不同的数据类型来实现
从节点发送请求到主节点请求同步数据主节点Master判断是不是第一次请求如果不是则会全量同步主节点master会执行bgsave生成一个RDB文件发送给从节点进行执行主节点master在记录RDB期间接收的其他命令会记录到reportbacklog日志文件中,再将日志文件发送给从节点去执行
全量同步
1.从节点slave发起同步请求,主节点判断是不是第一次请求并且获取到从节点slave发送过来的offset值2.主节点master从日志文件中获取offset之后的数据同步到从节点
增量同步(slave从机重启或后期数据发生变化)
单点Redis并发能力有上限的如果实现Redis并发能力,需要用到主从集群,实现读写分离
主从
监控
自动故障恢复
通知
哨兵选主规则:slave节点的offset值越大优先级越高
脑裂:由于网络断开导致
基于心跳机制 如果到期之后发现某节点没在规定时间响应为主观下线 如果超过指定数量的sentinel发现某节点没在规定时间响应为客观下线
概要
哨兵模式(提供了主从集群的自动故障恢复)Sentinel
哨兵
海量数据存储
高并发写的问题
集群中出现的问题
设置多个master,可以解决海量存储问题
每个master设置多个slave解决高并发写的问题
master之间通过ping来监测彼此的状态
分片集群的特征
集群
集群相关
主从,哨兵模式可以解决高可用和高并发
事务
Redis是纯内存,执行速度非常快
采用单线程的避免不必要的上下文切换竞争条件
Redis运用的是IO多路复用技术,非阻塞式IO
Redis为什么那么快
1.由于Redis是纯内存操作,它的性能瓶颈是网络延迟而不是执行速度,IO多路模型主要是实现了高效的网络请求2. 单个线程来同时监听多个socket,IO多路复用主要是epoll,和传统的select和poll不同的是 epoll不需要把用户进程逐个遍历Socket来确认,epoll会在socket就绪的同时把已经就绪的socket写入用户空间3. 命令恢复处理器:Redis6.0之后使用多线程来处理回复事件 命令请求处理器:Redis6.0之后命令的转换也变成了多线程,但是命令执行的时候仍然是单线程
能解释一下IO多路复用模型吗?!!!!
面试官问题
Redis的网络模型是 IO多路复用+事件派发的机制
其他相关问题
单点Redis的并发能力是有限的,我们需要搭建主从集群来提高并发能力实现读写分离主节点负责是写数据,从节点负责是读数据
全量同步: 从节点发送请求给主节点,主节点判断是不是第一次请求,如果是第一次请求会全量同步到从节点 主节点执行bgsave,生成RDB文件之后发送给从节点执行 在RDB执行期间,主节点会以命令的方式记录到缓存中(日志文件) 生成的命令文件 发送给从节点进行同步 增量同步: 从节点slave发送同步请求,主节点判断是不是第一次请求如果不是获取到从节点发送过来的offset值 主节点master从日志文件中获取offset之后的数据同步到从节点
Redis主从数据同步的流程
主从复制
哨兵模式
分片集群
Redis集群有哪些方案?
哨兵模式:实现主从集群的自动故障恢复(监控,自动故障恢复,通知)
如何保证Redis高并发高可用
主从1主1从+哨兵,单点不超过10G如果Redis内从不足可以给不同服务器分配独立的Redis主从节点
你们使用的Redis是单点的还是集群的,那种集群
Redis分片集群中引入了哈希槽的概念,Redis一共有16834个哈希槽,将这些哈希槽分配给不同的主节点master,根据key的有效部分计算哈希值,余数为插槽,寻找插槽所在实例
Redis分片集群中是怎么存储和读取的
由于主节点和从节点和Sentinel处于不同的网络分区,会有两个master。当服务器恢复之后会将老的master降级成从节点,重新同步maste数据导致数据丢失解决方式:设置最少从节点数量,设置主从同步时间
Redis集群脑裂该如何解决
Redis:AP思想保证高可用性CP思想的是Zookeeper
聚合查询
多表查询
数据量过大查询
深度分页查询
定位慢
Mysql执行计划
存储引擎
Sql底层的数据结构
聚簇和非聚簇索引
子主题
覆盖索引
总结:根据查询条件去查询,如果二级查询条件里没有相关的信息则回表查询
数据量较大,查询频繁——单表超过10万
尽量选择区分度较高的列作为索引,尽量建立唯一索引,区分度越高效率越高
常作为查询条件Where,OrderBy,GroupBy
如果字段长度较长,根据字段特点建立索引
尽量使用联合索引,联合索引很多时候可以用覆盖索引避免回表,提高效率
控制索引的数量,太多维护比较麻烦
创建表时,使用NOT NULL约束
索引创建的原则
正常情况下
违反最左前缀法则
违反了最左前缀法则
范围查询右边的列,不能使用索引
索引列上进行运算操作
字符串不加‘ ‘ 导致失效
模糊查询可能导致索引失效
索引失效的场景
索引
Sql优化经验
Mysql的优化
介绍一下当时产生问题的场景,接口测试的时候非常慢,压测结果大概五秒钟
我们系统中采用了运维工具(Skywalking)最终查出是sql的问题
Mysql中开启慢日志查询,设置两秒
Mysql中如何定位慢查询?
方案一:开源查询调试工具:Arthas 阿尔萨斯运维监控:SkyWalking
方案二:Mysql自带的慢日志查询
KEY和KEY_Len检查是否命中了索引
TYPE查看是否优化空间
EXTRA来看是否回表
可以使用Mysql自带的分析工具EXPLAIN
如何分析优化这条sql的?
概要:页面加载时间过长
索引是帮助Mysql高效获取数据的数据结构——提高查找效率索引对数据库进行排序,降低排序成本。减少CPU损耗
了解过索引吗什么是索引
font color=\"#4ccbcd\
索引的底层数据结构了解过吗?
将数据存储和索引放到了一块,叶子节点保留行数据——必须有只能有一个选取原则: 1.如果有主键,主键就是聚集索引 2.如果没有主键,第一个索引就是聚集索引 3.如果都没有,Innodb自动生成一个隐藏的rowid来生成主键
聚集索引
数据和索引分开存储,叶子节点关联的是对应的主键——可以有多个
二级索引
通过二级索引找到主键值,聚集索引中查找整行数据,这个过程为回表
回表查询
什么是聚集索引,二级索引——什么是聚簇索引,非聚簇索引什么是回表查询?
数据量大,表查询比较频繁
尽量使用联合索引
控制索引数量
常作为查询条件,排序,分组的字段
索引创建的原则有哪些?
违反了最左前缀法则,跳过了某一列
like查询导致了索引失效
范围查询右侧的列导致索引失效
给索引进行类型转换导致失效
在索引上进行计算导致索引失效
什么情况下索引会失效?回答细节:回答一些自己面试过的
用EXPLAIN进行分析
一级缓存也就是本地缓存基于Session级别的,一级缓存是一直开启的,查询到的数据会缓存到一级缓存中只作用再同一sqlsession中
二级缓存是全局的基于namespace级别的缓存,可以在多个sqlsession中共享
mysql的二级缓存?
覆盖索引+子查询先groupby排序之后查询
Mysql的超大分页如何解决
查询使用了索引,返回的列,必须在索引中能全部找到 1.使用ID查询,直接走聚集索引,一次性索引扫描,直接返回数据,查询效率高 2.如果返回的列里没有创建索引,容易触发回表查询,避免使用Select *
什么是覆盖索引?
表的优化: 设置合适的数据类型
left join是以左表为主,返回左表中的所有行,以及右表中和左表匹配的行。right join是以右表为主,返回右表中的所有行,以及左表中和右表匹配的行。而inner join不以任何表为主,它只返回符合条件的行。
SQL语句的优化: 避免使用SELECT * 使用索引避免索引失效 能用InnerJoin就不用LeftJoin和RightJoin,如果必须使用小表驱动大表如果是聚合查询,尽量使用union all代替union
主从复制和读写分离 读的操作要是多就用读写分离
谈谈你对于SQL的优化经验
面试官问题;
事务特性
隔离级别
Multi-Vesion-Concurrentcy-Control多版本并发控制,维护一个事务的多版本,使得读写没有冲突
隐藏字段
回滚日志:当使用insert,update,delete产生便于回滚的数据日志当insert产生时,undolog日志只会在回滚时需要,事务提交后立刻删除update,delete回滚时需要,MVCC也需要不会被立刻删除
undolog日志
RC级别下获取历史版本记录
RC
RR
是快照读SQL提取mvcc的数据依据,记录并维护系统当前的活跃事务id当前读:读取的最新版本记录,保证其他并发事务不能修改对读取的数据进行加锁快照读:读取数据的可见版本,也有可能是历史数据,不加锁的非阻塞 rc:读已提交每次select都会生成快照读 rr:仅在第一次的时候生成readview其他时都会复用ReadView
readView
MVCC
事务相关
主库提交事务之后,会将数据变更存储到二进制的Binlog文件中从库读取主库的二进制文件binlog,写入从库的中级日志RelayLog从库重做中继日志的事件,改变反应它自己的数据
面试官问题:主从同步的机制
核心是二进制文件也叫BinLog日志记录所有DDL(数据定义语言)语句和DML(数据操作语言)语句
主从同步
分库分表的时机:随着项目业务数据增多,业务发展迅速 达到一千万或20G以后
优化解决不了性能问题
IO瓶颈,CPU瓶颈
分库分表(解决存储压力)
以表为依据拆分不同的表到不同的库
垂直分库
以字段为依据根据不同的属性将不同的字段拆分到不同的表中将不常用的拆分出来,text和blob等大字段放到附件表中
垂直分表
垂直拆分
一个库拆分到多个库中
水平分库
一个表的数据拆分到多个表中
水平分表
水平拆分
拆分策略
分库分表相关的策略
其他面试题
ACID A:原子性:要么全部成功要么全部失败 C:一致性:所有的数据都要保持一致 I:隔离性:不受影响独立运行 D:持久性:一旦提交或者回滚改变是永久性的
事务的特性是什么?详细说一下
并发问题: 脏读:一个事务读到另外一个事务没提交的数据 幻读:查询的时候没有,当插入的时候数据存在则幻读 不可重复读:先后读取同一条数据,数据结果不同
隔离级别: 读已提交:能解决所有并发问题——一般不用 读未提交:能解决幻读和可重复读,无法解决脏读 可重复读:默认,只能解决幻读 串行化:什么都无法解决——放弃并发
并发事务带来哪些问题,如何解决,Msql默认的隔离级别是
redo log:记录数据页的物理变化,服务宕机可以用来同步数据undo log:记录逻辑日志,当数据回滚的时候可以进行恢复undo log保证数据的持久性,redo log保证数据的一致性和原子性
undo log和redo log的区别
MVCC:多版本并发控制,维护一个数据的多个版本,使得读写操作没有冲突分为三大块: 一,隐藏字段 1.trx_id(事务id)记录每一次操作的事务id,自增的 2.roll_pointer(回滚指针)指的是上一个版本的版本地址 二,undolog 1. 回滚数据存储老版本的数据 2.版本链多个数据并行操作某一行数据,记录不同事务的修改数据版本,通过roll_pointer来形成链表 三,ReadView解决一个事务查询选择版本的问题
事务中的隔离性如何保证的?(你解释一下MVCC)
Mysql
Bean安全问题
AOP是面向切面编程,将那些与业务无关但是对多个对象产生影响的公共行为和逻辑,抽取并且封装成一个可重用的模块这个模块叫做切面Aspect。减少重复代码,降低耦合度,提高代码复用性
记录操作日志
缓存处理:AOP切面拦截需要添加缓存的业务方法
Spring中内置的事务处理
AOP场景
事务原理
异常捕获处理失效
抛出检查异常可能失效
非Public方法导致失效
事务失效
AOP
构造函数必须与类名相同且不能有返回值
每个类可以有多个构造函数,如果没有写默认无参
伴随new去执行,不能自己调用由系统调用且一次
不能被继承,可以被重载
构造函数
或者@AutoWired
依赖注入
三个aware实现方法
Aware'接口
BeanPostProcesser-前置
自定义的初始化
Initializtion初始化方法
执行初始化方法
AOP增强使用的动态代理——JDK和CGLIB
BeanPostProcesser-后置(用于增强)
销毁
流程图
PathViriable:路径上传参数比如查询id之类的
Bean的生命周期
A依赖于B ,B依赖于A
二级缓存:二级缓存可以解决一般情况下的循环依赖,但是无法解决代理对象(增强)的循环依赖
三级缓存:能够解决大部分的循环依赖
实例化过程的循环依赖
解决方法:三级缓存
默认情况下循环依赖会导致死循环问题
循环依赖
Spring
1.首先浏览器发送请求之后会打到前端控制器中前端控制器————调度中心2.处理器映射器的主要作用是执行方法(前端控制器向处理器映射器查询handler方法(handler是getByid这类的方法)并执行)继续返回处理器执行链(拦截器和handler一起封装)给前端控制器3.假如没有拦截器会之间找处理器适配器去请求处理某一个方法之后返回ModleAndView给前端控制器处理器适配器(处理参数User user这些,返回值返回User返回R等什么的)4.最后前端控制器去找视图解析器,逻辑视图变成真正视图返回JSP
视图阶段(JSP)
返回结果通过@ResponseBody之间转成JSON并且响应,跳过了视图解析器
前后端分离开发(接口开发,异步请求)
执行流程
SpringMVC
1.当用户发送请求的时候首先找到DispatcherSevlet
2.DispatcherSevlet会去找处理器映射器HandlerMapper
3.HandlerMapping找到具体的处理器(某一个方法),判断是否有拦截器如果有打包回给前端控制器
4.前端控制器调用处理器适配器
5.处理器适配器会找到具体的处理器Controller中的某一个方法
6.Controller执行完成后会返回一个ModleAndView
7.ModleAndView会返回给处理器适配器,由适配器返回给前端控制器
8.最后由前端控制器将ModleAndView发送给视图解析器
9.视图解析后会返回一个View给前端控制器
10.前端控制器会根据View来渲染视图
视图版本JSP
6.方法添加ResponBody
7.通过HTTPMessageConverter来返回结果转换为Json进行响应
前后端分离版本
springMVC的执行流程
自动配置原理
SpringBoot
Spring框架中有一个Scope, 默认的值是Singleton,单例的
一般在Spring的Bean的中都是注入无状态的对象,没有线程安全问题,如果在Bean定义中修改了成员变量,那么就有线程安全问题,需要用到多例或者加锁解决
Spring框架中的Bean是单例的吗,如果是那它是线程安全的吗?
AOP是面向切面编程,将那些与业务无关的对多个对象产生影响的公共行为和逻辑,抽取公共的模块。降低耦合度。
记录操作日志——使用AOP的环绕通知+切点表达式通过环绕通知的参数获取请求方法的参数,之后保存到数据库
什么是AOP,你们项目中有没有使用到AOP
本质上是AOP事务,是对方法的前后拦截,在方法执行之前开启事务,在方法结束之后回滚或者关闭事务
Spring中的事务是如何实现的?
异常捕获处理失败:手动抛出异常
抛出检查异常,spring只会对RunTime事务进行回滚,我们需要配置rollbackFor属性为Exception
非public方法导致的失效,添加public
Spring事务中事务失效的场景有哪些?
通过BeanDe'finition获取Bean的定义信息
调用构造函数实例化Bean对象(实例化之后它先去调用构造函数,像依赖注入,接口实现方法等都没执行)
Bean的依赖注入:Set方法注入
处理Aware接口:一系列的以aware结尾的接口,实现接口之后重写最后执行对应的方法即可BeanNameAware,BeanFactoryAware,ApplicationContextAware
BeanPostProcessor-前置的Bean的后置处理器
初始化方法:InitialiZingBean
BeanPostProcessor-后置的Bean后置处理器:某一个对象使用代理时需要增强
销毁bean
SpringBean的生命周期
循环依赖:Spring中的循环依赖也就是循环引用,它是指两个或者两个以上的Bean互相持有对方,最终形成闭环
循环依赖在spring中是允许存在的,它使用三级缓存来解决大部分的循环依赖问题一级缓存:单例池,缓存已经经历了完整的生命周期,初始化完成Bean对象二级缓存:缓存早期的Bean对象(生命周期还没走完)——光建了构造函数三级缓存:缓存的是ObjectFactory,表示对象工厂,用于创建某个对象的(原始,单例都可)
Spring中的循环引用(依赖)?
由于Bean的生命周期中构造方法是第一个建立的,spring无法解决使用@Lazy进行懒加载,什么时候需要Bean对象什么时候再进行Bean的创建
构造方法出现循环依赖怎么解决呢?
面试相关的问题
它简化了Spring应用程序的开发和部署流程,Spring Boot通过自动配置的方式,可以根据应用程序的依赖和配置,自动配置和加载相应的功能模块Spring Boot内置了多种常用的Web服务器,不用依赖外部Web服务器它可以自动扫描和注册Spring组件、自动配置数据库连接池、自动配置事务管理等提供了丰富的起步依赖和高扩展性和灵活性
谈谈你对springboot的理解
一.SpingBoot项目的引导类上有一个注解@SpringBootApplication,这个注解对三个注解进行封装1.SpringBootConfiguration2.EnableAutoConfiguration3.ComponentScan 扫描包
二. EnableAutoConfiguration是实现自动化配置类的核心注解,通过Import注解导入对应的配置选择器内部是读取了该项目和项目引用的jar包的classPath路径下的META-INF/spring.factories根据指定条件去导入到Spring容器中
三,条件判断有像@ConditionOnClass这样的注解,判断是否有对应的加载文件如果有则加载
通过SpringBootConfiguration引入了EnableAutoConfiguration(负责启用自动配置功能)之后通过EnableAutoConfiguation引入了importSpring容器启动时,加载IOC容器会解析Import注解import引入了一个deferredImportSelector,它会使springboot自动配置类顺序在最后,方便扩展和增益读取所有的META-INF/spring.factories文件过滤所有的AutoConfiguartionClass类型的类最后通过Condition排除无效的自动配置类
SpringBoot的自动配置原理
最大连接数+最大等待数的数量最大连接数是8192,最大等待数是100
SpringBoot可以同时处理多少请求?
跨域只有在前端会发生,因为浏览器会有一个同源策略的东西,我们现在都是前后端分离的项目,前端和后端可能都是不同的端口
使用CorS的方式,可以实现一个WebMvcConfigurer这样的ben去重写addCorsMapping跨域映射
springBoot解决跨域问题?
Component,SerIvce,Controller,Respository:用于实例化Bean
Autowired:自动注入
Improt:Spring导入的类会加载到IOC容器中
Bean:存储到Spring容器中
Scope:标记Bean的范围
Aspect,Before,After,Around,PointCut:AOP切面编程
RequestMapping:以它为父路径
RequestBody:可以将http请求的JSON数据转成Java对象
ResponseBody:返回值转成JSON响应给客户端
RequestHandler
RestController:包含Controller+ResponseBody
RequestParam:前端的数据转到后端不一致问题可以做映射
SpringBootConfiguration:实现配置文件
EnableAutoConfiguration:打开自动配置
ComponentScan:组件扫描
Spring框架常见的注解
Mybaits是根据JDK的动态代理来实现spring的接口
spring是如何整合Mybaits管理mapper的接口的?
通过实现约定的规则来简化开发过程简化了开发流程,减少了学习成本,提高可读性,降低错误和冗余
主要就是约定大于配置
构建Web应用更简单
内置tomcat等Servlet容器
不需要XML配置
springBoot底层原理
SpirngMvc
SrpingBoot
Spring/SpringMVC/SpringBoot常用注解
使用了CGLIB创建目标对象的代理对象当调用方法时(比如查询OrderList)进入拦截器ivoke发现,判断orderlist是否为空如果使用延迟加载那么orderlist肯定为空,最后执行sql查询订单并封装再获取就拿到数据了
Myabatis的延迟加载
延迟加载
一级缓存:Perpetual 的HashMap本地缓存,作用域为Session,默认打开一级缓存
注意:1/2级缓存只要实现增删改操作都会被清空clear 只有会话提交关闭之后一级才可以转移二级 二级缓存要实现Serialiable
二级缓存开启
二级缓存:基于namespace和mapper 的作用域起作用的,不依赖于session 默认也是perpetual Hash来存储默认的关闭的
支持的一二级缓存
MyBatis
框架篇
1.读取mybatis的配置文件
2.构造会话工厂sqlsessionFactory
3.会话工厂创建SqlSession对象(包含SQL语句的所有方法)
4.操作数据库接口Executor执行器,负责缓存的数据维护
5.Executor有一个MapperStatement类型参数封装类型信息
6.输入参数映射
7.输出结果映射
Mybatis的执行流程?
Mybatis支持延迟加载,延迟加载的定义是需要用到数据的时候才进行加载
Mybatis支持一对一一对多的关联延迟加载
可以去配置LazyLoadingEnable=true/false默认关闭的
Mybatis是否支持延迟加载?
使用CGLIB创建目标对象的代理对象,之后进入拦截器invoke,判断是否为NULL 如果为NULL执行sql查询,获取到数据之后调用set方法设置属性值,最后得到数据
延迟加载的底层原理你知道吗?
一级缓存基于perputal的HashMap本地缓存,存储作用域为sql session,默认打开一级缓存
二级缓存作用域namespace,mapper的作用域,不依赖于session,需要单独开启,核心配置和mapper映射文件
Mybatis的一级二级缓存是否用过?
增删改的情况下
Myabtis二级缓存什么时候会清理缓存数据?
Nacos
Eureka
服务注册
Ribbon的负载均衡策略
自定义负载均衡策略
负载均衡
熔断
熔断和降级
降级
Skywalking
SpringCloud
Tomcat:默认最大连接数是200
Nginx,漏桶算法:本质上就是以固定的流量进行处理
网关,令牌桶算法
自定义拦截器
限流的实现方式
限流
分布式事务解决方案
TC(Coordination):事务协调者,维护全局和分支事务的状态,协调全局事务提交或回滚
TM(Manager):事务管理者:定义和开启全局事务的范围,提交和回滚全局事务
RM(Resource Manage):资源管理器:管理分支事务处理资源,于TC交谈记录分支事务于报告分支事务的状态并驱动分支事务提交或者回滚
seata
分布式事务
Seata的XA模式:XA模式保证强一致性等待各个分支事务都报告完事务状态之后才能提交或者回滚缺点是:等待时间过长
Seata的AT模式:保证了可用性AP如果事务提交之后undolog里存储的数据删除事务回滚就将undolog里的数据提取出来
TCC模式:两阶段提交
幂等:多次调用方法或者接口不会改变业务的状态,可以保证重复调用的结果和单词调用的结果一致
需要幂等的场景:由于网络波动导致的用户重复点击MQ消息重复应用使用失败或超时重试
数据库的唯一索引
token+Redis保证新增和修改
如果保证新增的幂等?
GET:方式 查询操作 天然的幂等POST:新增操作不是幂等delete:是幂等的 删除之后就没了PUT:如果以绝对值更新是幂等,如果增量更新不是幂等
分布式服务接口幂等
XXL-JOB
分布式任务调度
业务相关
异步发送(验证码,短信,邮件)MYSQL和Redis,ES之间的同步分布式事务
RabbitMQ的使用场景
重发
记录日志
保存数据库定时重发,之后删除数据库中的数据
消息没到交换机:通过Publisher Confirm机制来避免消息发送到MQ的过程中丢失当消息发送到MQ之后会返回结果给消费者,表示消息处理成功
MQ宕机:MQ默认存储在内存中,可以设置持久化功能保证消息不丢失
消费者确认:处理消息之后可以向MQ发送ACK回执,MQ收到ACK回执之后会删除数据
消息不丢失:有三种情况会导致丢失消息没到交换机队列中的消息丢失消费者没收到消息
消息重复队列
惰性队列:将消息存储到磁盘中,而非缓存中当消费者消费消息时候才会从磁盘中读取支持数百万条的数据
消息延迟堆积
消息可靠性
进入队列的消息会被延迟消费队列超时订单,限时优惠,和定时发布
什么是延迟队列?
延迟队列=死信交换机+TTL存活时间
延迟队列和死性交换机的区别?
过期消息,超时无人消费
投递的队列消息堆积满了,最早的消息可能会死信
basic.reject和basic.nack声明失败。消息的Requene消息设置为false
什么是死信? 消息不会被消费直接丢弃掉不会被消费掉
TIme-To-Live,如果队列中的消息TTL结束仍然没消费会变成死信,TTL分两种情况消息所在队列设置存活时间消息本身设置存活时间注:以短的为准
什么是TTL?
死信交换机
生产环境下使用集群来保证高可用
普通集群
镜像集群:本质是主从模式
仲裁队列
普通集群,镜像集群,仲裁队列
高可用机制
RabbitMQ常见问题
我们当时采用RabbitMQ来保证Mysql和Redis双写一致性1.开启生产者确认机制publisher-confirm确保生产者的消息能达到队列2.开启持久化功能保证,消息未消费前在队列中不丢失3.开启消费者确认机制为AUTO,消费者处理完成后自动提交ACK给MQ发送消息4.开启失败重试机制,重试次数过多会发送给异常交换机,人工处理
RabbitMQ如何保证消息不丢失?
因为当时设置的是自动确认机制,但是由于服务器宕机了,服务重启之后重复消费了因为我们当时处理的支付设置了一个唯一标识,再处理的时候去数据库查询了一下是否存在,如果存在就不需要重复消费了(唯一标识ID)还有一种方式幂等方案:使用Redis分布式锁,数据库锁等
RabbitMQ的重复消费问题如何解决?
当时是用了什么业务用到了延迟队列?(超时订单,现时优惠,定时发布)
延迟队列就用到了 死信+TTL消息存活时间来实现的
消息超时没消费就会变成死信(拒绝被消费,队列满了)
RabbitMQ死性交换机是怎么回事?延迟队列有了解过吗?
1.增加更多的消费者
2.扩大队列容积,采用惰性队列X-queue-mode为lazy,即为惰性队列
3.消费者内开启线程池加快消息处理速度
如果有一百万条消息堆积在RabbitMQ,如何解决(消息堆积如何解决)?
我们当时在生产环境下,采用的镜像模式搭建的集群
镜像模式就是一主多从,所有操作都由主节点进行完成,同步给从节点
主机宕机之后,从机会代替成为心的主机(主从同步完成之前就宕机了)
使用仲裁队列,和镜像模式一致但是他是使用的是Raft协议保证强一致性
如果数据丢失了如何解决?
RabbitMq高可用机制了解过吗?
发送消息到broker丢失:
消息在broker中存储丢失
消费者从broker接收消息时候丢失
消息不丢失
保障消息在同一分区下,才能保障消息的顺序性
消息顺序性
集群模式
为什么不能多设置几个ISR?因为ISR是同步保存的数据 性能会低于异步保存的数据
分区备份机制
不受单台服务器限制,处理更多数据
消息分区
磁盘顺序读写提升效率
顺序读写
数据缓存到内存
页缓存
减少上下文切换
零拷贝
减少磁盘IO和网络IO
消息压缩
打包发送减少开销
分批发送
高性能设计
文件存储机制
数据清理机制
数据存储和清理
Kafka
生产者发送消息到broker失败设置异步回调方式发送,通过回调获取失败后的信息之后重试、
消息在broker存储中丢失发送确认ack,选择all,所有副本都参与保存后确认
消费者从broker接收消息之后丢失KafKa消费消息都是按照offset进行消费的,默认情况下是每隔五秒提交一次,如果重平衡之后会导致数据丢失关闭自动提交偏移量,开启手动提交偏移量最好顺同步+异步提交
关闭自动提交偏移量,开启手动提交偏移量同步+异步提交幂等方案
卡夫卡的重复消费问题如何解决?
KafKa如何保证消息不丢失?
默认情况下无法保证消息的顺序性一个topic数据可能存储在不同的分区,每个分区都有一个按照顺序存储的偏移量可以发送消息时指定分区号或者是按照业务设置相同的key(通过key的hash值来选择分区)
KafKa如何保证消息顺序性
主要有两个层面:第一个是集群Kafka的集群指的是多个broker实例组成,其中一台宕机,不影响其他的broker服务第二个是提供了复制机制复制机制是保障Kafuka高可用的,一个topic有多个分区,每个分区有多个副本,一般情况下是一个leader和多个foller副本所有副本的内容都是不同的。如果leade发生故障,会将其中一个foller升级为leader
ISR指的是同步复制保存的数据,foller分为两类一类是ISR 一类是普通。同步的好处是数据更完整所以leader选举会优先选ISR中的foller
你能讲一下复制机制中的ISR吗?
Kafka的高可用机制了解过吗?
Kafka中的topic数据存储在分区上,分区文件过大会分段存储segment 是以索引index和日志文件log的方式存储分段的好处就是查找方便和便于清理日志有两个日志清理策略超过默认七天自动清理日志文件到达阈值会自动清理最久的都可以 通过broker中的配置文件进行设置
Kafka的数据清理机制了解过吗?
消息分区:不受单台服务器的限制,不受限的处理更多数据
顺序读写:磁盘顺序读写,提升读写效率
零拷贝:减少上下文切换
页缓存:磁盘中的数据缓存到内存中,可以直接直接对内存访问
KafKa的高性能了解过吗?
消息中间件
微服务篇
注册中心Eurea,Nacos
负载均衡Ribbon
远程调用Feign
服务保护Sentinel
网关Zuul/Gateway
SpringCloud 的5大组件有哪些?
我们当时使用的是Eureka作为服务注册中心,这个也是SpringCloud的核心组件之一服务注册:服务提供者将自己的信息注册到eureka,由eureka保存信息比如ip,端口等服务发现:消费者向eureka,拉去服务信息和列表,如果服务提供者有集群利用负载均衡算法选择一个发起调用服务监控:服务提供者每隔30s会向eureka发送心跳,如果90s eureka没有收到心跳则会移除
服务发现和注册是什么意思?,springCloud如何实现服务注册发现?
nacos和Eureka都支持服务注册和服务的拉取都支持服务提供者以心跳机制来检测
Nacos支持服务端主动检测提供者状态,临时实例会采用心跳机制,非临时实例采用主动检测状态Nacos支持服务列表变更的推送机制Nacos的非临时实例不会被删除,临时实例的心跳不正常会被剔除Nacos集群默认是AP架构,如果存在非临时实例则使用CP模式,Nacos使用AP模式Nacos支持服务的配置中心,eureka只支持服务注册
你能说一下nacos和Eureka的区别吗
使用的是Ribbon组件来实现负载均衡,用feign发起远程调用的时候底层的负载均衡就是Ribbon
你们项目的负载均衡是如何实现的?
简单轮询
权重轮询:响应时间越长,权重越小
随机轮询
区域可用服务器进行服务器选择
常见的负载均衡策略有哪些?
创建类实现IRule接口(全局)在yml里实现负载均衡策略(局部)
自定义负载均衡如何实现
就是一个服务失败可能导致其他服务都失败的场景
使用熔断和降级策略降级确保服务不会崩溃于feign接口整合熔断是10s内超过百分之50的失败率会熔断,之后进入半开放状态每隔五秒发送请求如果失败继续熔断,如果成功恢复正常
也可以用限流来预防
什么是服务雪崩
服务注册和发现:Eurea或者nacos
服务调用和负载均衡:Ribbon和feign
服务熔错和熔断:Hystrix来实现熔断机制
服务网关和路由:Zuul和gateway提高安全性和可靠性
分布式追踪和监控:Zipkin来提供可视化的数据展示和分析工具
SpringCloud的原理
1.先来介绍一下业务什么时候去做限流QPS最高可以达到2000多,平时在10-50之间应对突发流量做限流根据压测结果系统最大承受量在1000
2.用的nginx限流,使用的是漏桶算法来实现过滤,以固定的速度处理请求,应对突发流量
3.用的网关限流,用的令牌桶,网关中提供RequestRateLimiter来进行限流
你们项目中是如何做的限流,怎么做的?
CAP定理(一致性,可用性,分区容错性) 一致性和可用性无法同时满足也就是只能实现AP或者CPBASE理论 基本可用 软状态 最终一致性解决分布式事务的思想模型 最终一致性:分别提交,如果不一致再恢复数据AP 强一致性:等待彼此结果CP
解释一下CAP和BASE理论
你们采用的哪一种分布式事务解决方案(简历上写了微服务项目,MQ,Seata框架:XA,AT,TCC)
多次调用方法和接口不会改变业务,重复调用的结果和单次结果一致
新增数据可以使用数据库的唯一索引
新增和修改业务用的token+Redis性能好 第一次请求会携带一个token进入redis,返回给前端 第二次请求业务处理,携带之前的token,到redis进行验证如果有则执行业务并且删除,如果没有之间返回不处理业务
分布式服务接口的幂等性如何去设计?
面试相关问题
Vector数组结构,线程安全
ArrayList 数组结构,非线程安全
LinkedList 链表结构,非线程安全
List有序,可重复
HashSet哈希表结构——LinkHashSet 哈希表和链表结构
TreeSet红黑树结构
Set 无序,唯一
Collection单列集合
HashTable 哈希表结构 线程安全——Properties
HashMap 哈希表结构 非线程安全——LinkHashMap 哈希表和链表结构
ConcurrentHashMap哈希表结构线程安全
TreeMap 红黑树结构
Map双列集合
1
2
3
4
时间复杂度相关
空间复杂度相关
数据结构相关
根据数组索引获取元素的时候,会用索引和索引公式来计算内存对应的元素数据:数组的首地址+索引*存储类型的大小,如果用1开始会做减法
索引为什么从0开始1开始不行吗?
ArrayList是基于底层动态数组实现的1.arraylist初始容量为0第一次添加数据的时候初始容量为102.arraylist进行扩容的时候是原容量的1.5倍,每次扩容都需要拷贝数组
ArrayList底层的实现原理?
只是声明和实例了一个arraylist 并没有扩容
ArrayList list=new Arraylist(10)扩容了几次?
数组转list,用的是Arrays工具类中的aslist方法list转数组,用的是list中的toArray方法
Arraylist.aslist转换list之后,修改数组内容会受到影响,底层使用的是arrays类中的内部类arraylist来构造集合传入的集合进行包装而已
list用了toarray转数组之后修改内容不会受到影响,他是进行了数组的拷贝和原来没啥关系
把list转数组后,数组受到影响吗?把数组转list,list受到影响吗?
如何实现数组与list之间转换?
1.arraylist是动态数组的数据结构实现 linklist是双向链表的数据结构实现2.arraylist可以通过索引查询 查询效率高 但是新增删除效率低,连续的节约内存 linklist需要遍历查询 效率低,linklist新增删除效率低,存储数据两个指针 内存比较多
1.在方法内使用,局部变量是线程安全的
2.使用线程安全的arraylist和linklist——底层加synchronized锁
如何保证linklist和arraylist线程安全?
ArrayList和LinkList的区别?!单向链表只有一个方向,节点只有有一个后继指针next双向链表有两个方向,有后继指针和前驱指针
List相关面试题
每个节点最多有两个叉,左子节点和右子节点
什么是二叉树?
又叫二叉搜索树,也叫二叉查找树,左子树节点的值要小于这个节点的值,右子树节点的值要大于这个节点的值
什么是二叉搜索树?
红黑树是一种自平衡的二叉搜索树查找添加删除都是 LogN
红黑树
散列表又称哈希表,根据key直接访问value数据结构,由数组演化过来的,利用了数组支持下标随机访问的特性
什么是散列表?
散列冲突又称哈希冲突,哈希碰撞。多个key映射到同一数组下标地址
散列冲突
散列冲突——链表法
散列表
HASHMap
HashMap相关面试题
底层用的hash表的数据结构,数组和链表或红黑树当数组中出现put的元素时候,利用key的hashcode计算出当前对象的元素在数组的下标如果hash值出现相同的key有两种方案1.key相同i,覆盖原值2.key不同,将key放入链表或红黑树中
HashMap的实现原理
1.7采用的是拉链法,数组+链表结合,如果发现冲突则冲突的值加入链表即可1.8 数组长度大于等于8,数组长度大于64会转换成红黑树 (数组+链表+红黑树)
hashmap1.7和1.8区别
hashmap中put方法的执行流程
我们在添加元素或者初始化的时候会使用resize方法进行扩容,第一次添加数据初始化长度为16扩容之后会重新创建一个数组,将老节点的数据移动到新数组中
讲一讲hashMap的扩容机制
面试题
集合相关问题
线程与进程的区别
单核CPUI:串行执行:线程轮流使用CPU的做法叫并发
多核CPU
并行与并发的区别
继承Thread类
实现Runnable接口
实现Callable接口
线程池创建线程
线程创建的方式有哪些
runnable和callable有什么区别
run():普通方法可以执行多次
start():不能开启多次只能开启一次
线程的run()和start()有什么区别
线程状态
new——runnable——desotry
BLock
wait
sleep
状态之间如何变化?
状态
线程包括哪些状态,状态是如何变化的
wait和sleep方法的不同
新建三个线程如何保障顺序执行
notify随机唤醒一个wait线程notifyAll 唤醒所有的wait线程
notify()和notifyAll有什么区别
如何停止一个正在运行的线程
线程的基础知识
1.进程是正在运行的程序实例(比如浏览器等) 进程中包含多个线程,每个线程执行不同的任务2.不同的进程使用不同的内存空间(打开IDEA和打开浏览器的内存空间不一样),当前进程下的所有线程可以共享内存空间3.线程更轻量,切换成本低
线程与进程的区别?
并行和并发有什么区别?
实现Thread类
线程池创建方式,不调用start方法
Runnable接口的run方法没有返回值Runnable无法向上抛出异常只能内部消化,callable可以向上抛出异常Callable有返回值 配合futrue或futuretask方法获取异步执行结果
那你能说说runnable和callable的区别吗
Start方法用来启动线程,根据run方法调用run方法所定义的代码逻辑,只能被调用一次
run:封装了要被线程执行的代码(普通代码),可以调用多次
启动线程的时候可以使用Run方法吗,run()和Start()方法有什么区别?
创建线程的方式有哪些?
New新建状态,Runnable可运行状态,block阻塞,wait等待,Time-waiting睡眠,Terminated终止
创建线程对象是新建状态调用了start方法变成可运行状态加锁synchronized或lock变成阻塞状态调用wait进入等待状态 用notify唤醒调用sleep进入睡眠状态执行结束是终止状态
线程包括哪些状态?状态之间如何切换的?
使用Join方法,比如ABC ,A正在运行 B 就可以用Join A来保障下一个进程是自己的
新建T1 T2 T3如何保障顺序运行
notify随机唤醒一个,notifyall唤醒全部线程
notify和notifyall区别
都能适当放弃CPU的使用权sleep等待响应时间后会醒来,wait需要唤醒sleep是Thread的静态方法,wait是Object成员方法锁特性不同!wait方法执行后会放弃对象锁,其他线程可以使用sleep方法基于synchroniezd代码块执行不会放弃对象锁
wait和sleep方法的区别
使用Interrupt方法中断线程
如何停止一个正在运行的线程?
synchronized采用互斥的方法让同一时间最多只有一个线程能获取锁,其他线程想获取锁的时候会被阻塞住
MonitorMontior被叫做监视器:它是JVM实现的 由C++语言编写Monitor中有三种状态:1.waitSet:关联调用wait方法的线程,处于waiting状态的线程2.EntrySet:关联没有抢到锁的线程,处于Blcoked状态的线程3.Owner:储存当前获取锁的线程,同一时间只能有一个线程可以获取
synchroniezd的底层原理
Monitor属于重量级锁:它涉及到用户态和内核态的切换,和进程上下文的切换成本较高,性能较低
Monitor属于重量级锁
偏向锁和轻量级锁:主要解决在没有多线程竞争下或者没有竞争下场景,因使用传统锁造成性能开销问题
轻量级锁
偏向锁
锁升级
Synchronized的底层原理——进阶
Java内存模型
加载某一个类,先委托上一级的加载器进行加载,如果上级加载器也有上级,则会继续向上委托,如果该类委托上级没有被加载,子加载器尝试加载该类
CAS compare and swap(比较再交换) 它是乐观锁,它主要保证无锁区域的线程操作共享数据的原子性CAS本质上是乐观锁,不怕别的线程修改变量,改了之后通过自旋的方法重试
CAS如何保证原子性?
修改的前提是旧内存和主内存的数据一致
CAS数据的交换流程:
CAS的底层实现
CAS
禁止指令重排
线程间的可见性
Volatile
AQS 和synchronized的区别
AQS(Abstarct Queue Synchronized 抽象队列同步器 也是锁机制
可重入锁优点:可中断,可以设置超时时间,可以重入 可以设置超时时间
实现原理:主要利用AQS队列(主要)+CAS来实现的,支持公平锁和非公平锁
ReentractLock的原理
死锁的诊断:使用JDK自带的工具JPS:输出JVM运行中的进程状态信息Jstrack:线程堆栈信息
jconsole:位于java安装目录 bin目录下
VisualVM:故障处理工具位于java安装目录bin目录下
死锁产生的条件一个线程同时获取多把锁
采用了segment的设计,通过hash值来计算位置
1.7版本的concorrenthashmap:用的是分段数组+链表实现
1.8放弃了segment数组臃肿的设计,和hashMap的数据结构是一样的:数组+红黑树+链表采用CAS自旋+synchronized 来保证并发安全进行实现
JDK1.8之后采用数组+链表/红黑树
ConcorrentHashMap
线程中的并发安全
corePoolSize 核心线程数
MaximumPoolSize 最大线程数:核心线程数+救济线程最大数目
KeepAliveTime生存时间
unit时间单位
workQueue工作队列
threadFactory线程工厂
handler拒绝策略
线程池的执行原理
LinkBlockingQueue:单向链表,默认无界支持有界,需要两把锁 锁头尾
ArrayBolckingQueue:强制有界,数组,一把锁
线程中有哪些阻塞队列:数组结构的有界阻塞队列链表结构的有界阻塞队列
核心线程数大小2N+1
I/O密集型:文件读写,DB读写,网络请求
核心线程数N+1
CPU密集型:计算型代码,bitmap转换
确定核心线程数
线程池的核心参数
创建固定线程数的线程池:任务量已知,比较耗时
单例化的线程池,按顺序执行的任务
可缓存的线程池:任务比较密集,任务执行时间较短
提供延迟和周期执行
线程池的种类有哪些
为什么不建议使用Executors创建线程池
线程池
Semaphore使用步骤
ThreadLoacl概述
强引用
弱引用
软引用
虚引用
ThreadLocal内存泄漏问题
使用场景(重点)
强引用:最常用的线程类型,它不会被垃圾回收
软引用:描述一些有用但是非必须的对象,用户实现内存敏感的缓存
弱引用:非必须的对象,不管内容是否足够都会被回收
虚引用:用于对象被垃圾回收的状态
并发编程篇(多线程相关面试题)
1.synchronized采用互斥的方式来确保同一时间,只有一个线程能持有锁2.它是由底层montiro来实现的,monitor是JVM实现的 由C++编写3.Monitor内部有三个属性,Owner,EntrySet,waitSet4.Owner是关联获取锁的线程,同一时间只能有一个,EntrySet是关联处于阻塞状态的线程,waitSet是管理处于等待状态的线程
Synchronized中有三种锁,分别是轻量级锁,偏向锁和重量级锁分别对应锁只被一个线程持有,不同线程交替持有,多线程竞争锁的情况重量级锁:底层使用Monitor来实现,涉及到用户态和内核态的情况,进程上下文切换,开销较高轻量级锁:适用于没有竞争的条件下,每次修改都是CAS操作保证原子性偏向锁:一个线程长时间的持有锁,第一次获取锁的时候会通过CAS操作,之后线程获取锁时就判断 id是否存在即可而不是开销比较大的CAS指令
monitor属于重量级锁,你了解过锁升级吗?
Synchorniezd的底层原理
JMM定义了共享内存和多线程程序的读写操作规范,保证指令的正确性JMM把内存分为两块,一种是私有的工作区域,一种是所有线程的共享区域线程和线程间是互相隔离的,线程和线程的交互需要用到主内存
你谈一谈JMM(JAVA的内存模型)
CAS 的全程是compare and Swap 对比和交换,是一种乐观锁的思想,无锁状态保证数据的原子性操作共享变量的时候使用的是自旋锁效率更高CAS底层调用的是unsafe类,是操作系统提供的CAS的使用场景比如AQS框架,AtomicXXX 等
乐观锁:不怕别的线程来修改变量,假如被修改之后乐观锁会通过自旋锁不断重试
悲观锁:通过加锁的方式来防止其他线程来修改变量
乐观锁和悲观锁的区别
CAS你知道吗?
保证线程间的可见性:一个线程对共享变量的修改对另外一个线程可见
禁止进行指令重排序:用volatile修饰共享变量会在读 写共享变量时加入不同的屏障禁止其他读写操作越过屏障,达到组织重排序的效果
谈一谈你对Volatile的理解
Abstract Queue Synchoronized 多线程的队列同步器,它是作为基础框架。ReentractLock用的就是AQS思想,本质上是一种锁机制AQS内部维护了一个先进先出的队列,作为存储的排队进程AQS内部还有一个属性state 为1则线程获取资源,对states修改的时候用到了CAS操作(乐观锁),保证了原子性
什么是AQS
基于CAS+AQS队列来实现的是可重入锁,调用lock方法获取锁之后再次调用lock不会被阻塞支持公平锁和非公平锁,无参默认是非公平锁,传参设置公平锁
什么是RenntrackLock
1.两者都属于悲观锁:都具备互斥,同步,锁重入功能Lock具备synchronized不具备的功能,比如公平锁,可打断,可超时Lock适合不同的场景实现,RenntrackLock2.synchronized 基于JVM实现的 源码是C++Lock 是接口基于JDK实现 java实现3.性能层面上看,synchronized做了很多优化,偏向锁,轻量级锁但是竞争激烈的情况下lock更好的性能
Synchronized和Lock有什么区别
一个线程同时获得了多把锁
java文件夹内bin目录下有两个自带的监控工具,jconsole和VisualVm
如果进行死锁诊断?
死锁产生的条件:
1.底层数据结构JDK1.7使用的是分段数组+链表实现的方式JDK1.8使用的是数组+链表/红黑树的方式2.加锁的方式1.7使用的是segment 底层使用的是Reentracklock,来实现的高并发1.8使用的是CAS添加新节点,采用synchronized锁定链表或者红黑树的首节点分段更细致,性能更好
ConcorrentHashMap是线程安全的,它通过使用segment分段式锁允许多个线程同时读写映射提高并发性ConcorrentHashMap不允许使用null来进行键或者值,会抛出异常如果程序多线程的ConcorrentHashMap更好的选择,如果是单线程的用hashmap更适合性能更好
聊一聊ConcorrentHashMap!!!!
Synchronized,lock
原子性
volatile,synchronized,lock
可见性
有序性
并发出现问题的根本原因,java如何保证多线程的安全
提交任务之后,判断核心线程数是否为满 如果没满将线程放在工作队列中如果满了,线程放在阻塞队列中。如果都满了将线程放到救急队列中,当救急队列执行完毕之后判断阻塞队列是否存在,如果工作队列仍然使用救急队列将阻塞队列的线程进行处理。如果都满了会使用拒绝策略1.默认是直接抛出异常2.直接丢弃任务3.设置最靠前的丢弃
核心线程数,最大线程数,救急线程,救急线程的存活时间,阻塞队列,线程工厂,拒绝策略
线程池的执行原理知道吗?
ArrayBlockingQueue
LinkBlockingQueue
线程中有哪些常见的阻塞队列
如果是高并发,执行任务较短的可以设置N+1,减少上下文切换
并发不高,任务执行比较长:通常情况下I/O密集型任务 CPU核数*2+1计算密集型任务 CPU核数+1
如何确定核心线程数?
newFixedThreadPool:固定大小线程池,控制最大并发数
newSingleThreadExecutor:单例化线程池,任务按指定顺序执行
newCachedThreadPool:可缓存的线程池,可以灵活回收空闲线程
newScheduledThreadPool:可以执行延迟任务的线程池,适合周期化
线程池的种类有哪些?
可能会堆积大量请求导致OOMOOM:out of memory 内存用完了
可能会创建大量线程导致OOM
ES数据的批量导入:当时项目上线之前,我们需要把数据库的数据一次性同步到es索引库中,当时数据量好像在1000万左右容易造成OOM异常,我们使用了线程池的方式导入,使用了CountDownLatch来控制一次性加载过多,防止内存溢出
数据汇总:用户下单之后需要查询数据,包含订单信息,商品信息,物流信息。不同的微服务实现如果多个接口没有依赖关系,我们可以使用线程池+future来提升性能
异步线程(线程池):异步线程调用下一个方法提高响应时间
线程池的使用场景(你们在哪里用到了线程池)
使用Semaphore是JUC包下的一个工具类,底层是AQS,限制执行数量。常用于限流acquire请求信号量,信号量-1release释放信号量,信号量+1
如何控制某个方法允许并发访问线程的数量
ThreadLoacl可以实现资源对象的线程隔离,避免线程安全问题
ThreadLoacl实现了线程内的资源共享
每个线程内有一个ThreadLocalMap类型的成员变量,用来储存资源对象调用set方法作为Key存储到ThreadLocalMap集合中调用get方法查找关联值调用remove方法移除线程管理的资源值ThreadLocalMap中的key是弱引用,值为强引用,key会被GC释放内存,value则不会需要用remove手动释放
谈谈你对ThreadLoacl的理解
线程私有的内部保存用于保存字节码的行号,用于记录执行的字节码指令的地址
程序计数器
用于保存对象实例,数组,当堆没有内存空间可以分配给实例,抛出outofMemory异常OOM异常
1.7和1.8的区别是什么?
Java堆
每个线程运行时,所需要的内存叫虚拟机栈
每个栈都有多个栈帧组成,每个方法需要的内存
因为是局部变量,每次线程调用方法都会新建一个,每个线程一份所以是线程安全如果StringBuilder是成员变量所有线程共享
帧栈过多导致栈内存溢出,递归调用
虚拟机栈
各个线程共享的内存区域
存储类的信息,运行时常量池
虚拟机启动的时候创建,关闭虚拟机时候释放
方法区
直接内存并不属于不属于JVM的内存结构,不由JVM进行管理。用于数据缓冲区,分配回收成本较高,读写性能高
和常规IO相比减少了Java堆内存和系统内存的互相复制
直接内存
JVM的组成
JVM只会执行二进制文件,类加载器的作用是将字节码文件加载到JVM中,从而让Java程序启动起来
类加载器是什么
双亲委派模型!!
避免某一个类会被重复加载,父类被加载后无需被加载保证唯一性保护类的API不会被修改
JVM的双亲委派机制特点
类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了︰加载、验证、准备、解析、初始化、使用和卸载这7个阶段。其中,验证、准备和解析这三个部分统称为连接(linking)
类装载执行过程
类加载器
引用计数法
哪些对象可以作为GCRoot?
可达性分析
什么是垃圾回收?
将垃圾分为两个阶段一个是标记-一个是清楚利用可达性分析算法得到垃圾并标记之后对这些标记的可回收内容进行垃圾回收内存碎片问题比较严重
标记-清除算法
复制算法
标记-整理算法:性能有一定影响
垃圾回收算法
堆被分为了两份:新生代 :老年代=1:2
分代回收
Serial新生代,复制算法
Serial-all老年代,标记-整理算法
串行垃圾回收器:适合堆内存较小,个人电脑
Parallel New 新生代,复制算法
Paraller Old 老年代 标记-整理
并行垃圾回收器:JDK默认的垃圾回收器
并发的,用标记-清除,老年代的垃圾回收
并发垃圾回收器:垃圾回收时,应用可以适用
G1具体
G1垃圾回收器
JVM的垃圾回收器
垃圾回收
war包部署在tomcat
jar包部署在启动参数设置
设置堆的空间大小
虚拟机栈的设置
年轻代的Eden区和两个survivor区大小比例 8:1:1
设置垃圾回收器
Java内存泄漏
CPU飙高
JVM调优的参数
JVM的实践
JVM
线程私有的,每个线程只有一份,内部保存字节码和行号用于记录正在执行的字节码指令的地址
什么是程序计数器?
Java堆主要是保存对象的实例和数组,当内存不够则抛出OOM异常由新生代+老年代组成
1.7有一个永久代,存储类信息,静态变量常量等1.8移除永久代,存放到本地内存元空间中防止溢出
java1.7和java1.8的区别
你能给我详细的介绍Java堆吗?
每个线程所需要的内存叫虚拟机栈
每个栈由多个帧栈组成,对应调用方法所需要的内存
每个线程只能有一个活动帧栈,对应当前执行的方法
什么是虚拟机栈?
垃圾回收主要指的是堆内存
垃圾回收是否涉及栈内存
栈帧过大导致线程数变少
栈内存分配越大越好吗
局部变量没有逃离方法作用范围是线程安全的
局部变量引用了对象容易造成线程不安全问题
方法内局部变量是线程安全的吗?
栈帧过多导致内存溢出,递归
什么情况下会导致栈帧过多
栈内存一般存储局部变量和方法调用,堆内存用来存储java对象和数组的。堆会被垃圾回收,栈不会
栈内存是私有的,堆内存是共有的
堆栈的区别是什么?
主要存储类的信息,运行常量池
虚拟机启动时候启动,虚拟机关闭时候释放
常量池可以看做一张表,虚拟机指令根据这张表找到执行的类名等类被加载之后,常量池信息会被放到常量池中,符号地址改编成真实地址
介绍下运行时常量池?
能不能解释一下方法区?
直接内存并不属于不属于JVM的内存结构,不由JVM进行管理。用于数据缓冲区,分配回收成本较高,读写性能高
你听过直接内存吗?
启动类加载器
扩展类加载器
应用类加载器
自定义加载器
类加载器有哪些?
1.避免某一个类会被重复加载,父类被加载后无需被加载保证唯一性2.保护类的API不会被修改
JVM为什么用双亲委派机制?
什么是双亲委派模型?
什么是类加载器?
加载:查找和导入class文件
验证:保证加载类的准确性
准备:为类变量分配内存,设置类的初始值
解析:类的符号转换成直接引用
初始化:对类的静态代码块实行初始化操作
使用:执行用户代码
卸载:JVM销毁创建的class对象
类装载的执行过程
当一个对象或者多个对象没有任何的引用可以指向它,那么这个对象就是垃圾,则可能会被垃圾回收器回收通过可达性分析法(更优)引用技术法:多引用导致内存泄露
对象什么时候可以被垃圾回收
标记-清除算法:用可达性算法找到垃圾,之后清除,效率高但是有磁盘碎片不连续
标记-整理算法:将存活的对象向另一边移动。无碎片效率低,适合老年代使用
复制算法:内存空间一分为二每次只用一块,正在使用的对象复制(复制之后自动就整理了)到另外一个内存空间之后清空,交换两个内存的角色无垃圾碎片,使用率低,适用年轻代
JVM垃圾回收算法有哪些
堆的区域划分堆被分成了两份新生代和老年代,1:2的比例关于新生代内部分为了三个区域,一个是elden,幸存者区(from,to)
对象回收分代回收策略新创建的对象会被放到elden区当elden区不同的时候会标记elden和from存活对象放到to区之后删除elden和from区的内存如果elden区又满了,标记to存活的对象放到from区中最多十五次之后会被放到老年代中
MinorGC,MixedGC,FullGC区别是什么MinorGC新生代的垃圾回收暂停时间短MixedGC新生代和老年代的部分垃圾回收FullGC是新生代和老年代的全部垃圾回收暂停时间长
JVM的分代回收?
SerialGC,SerialOld GC 针对新生代的用的复制算法,针对老年代的用的标记-整理
串行垃圾回收器
并行垃圾回收器 Parallelnew 针对新生代复制,Parallel针对老年代标记整理
并发垃圾回收器 :针对老年代 用的标记-清除
JVM有哪些垃圾回收器
强引用:只要GC Roots能找到,就不会回收
软引用,配合softReference,垃圾多次回收内存仍然不够的时候会回收
弱引用,配合weakReference,只要进行垃圾回收就会把弱引用的对象回收
虚引用:配合引用队列使用
强引用,软引用,弱引用,虚引用
war包部署tomcat
jar包在启动参数
JVM调优参数在哪设置?
堆空间的设置
设置垃圾回收收集器
JVM调优参数有哪些?
JVM调优工具
内存泄漏主要指的是堆内存,大对象不被回收的情况
Java内存泄漏的排查思路
使用top命令查看CPU占用情况
top命令可以看到那个线程占用内存较高
ps命令查看进程中的线程信息
jstrack命令查看线程中的哪些进程出现问题
CPU飙高 的排查方案和思路!
框架中的设计模式
简单工厂模式
工厂方法模式
抽象工厂模式
工厂+策略模式:订单的支付策略物流运费阶梯计算打折促销300 9折 2008折只要代码中有冗长的if else或者switch分支都可以策略模式优化
策略模式
避免请求发送者,和多个请求处理者耦合在一起,所有的请求处理者通过前一个对象记住其下一个对象的引用而形成一条链请求发生之后可以沿着这条链找到有对象处理它为止
责任链的设计模式
责任链模式
项目中的项目模式!
单点登录/SSO是什么?:用户只需要登录一次就可以访问所有信任的应用系统
JWT如何解决单点登录?
解释下单点登录:1.介绍自己项目中所涉及的单点登录(如果没有可以说实现思路)2.使用JWT来解决单点登录 I:用户访问其他系统之后,网关会判断token是否有效 II:token无效的情况下会返回401,前端会跳转到登录页面 III:用户发送登录请求之后会返回一个浏览器token,将token存放到cookie中 IV:再访问其他服务器之后,需要携带token,通过网关统一验证后路由到目标服务
单点登录这块你是怎么做的?
五张表的结构
五张表结构的例子:
三个基础部分组成:用户,角色,权限
后台管理系统开发经验。介绍RBAC权限模型和五张表的关系(用户,角色,权限)使用什么样的权限框架?springsecurity
权限认证如何实现的?后台管理系统,后台更注重权限认证,RBAC模型来指导实现权限Role Base Access Control
对称加密:文件加密和解密使用的是相同的密钥。加密也可以用来解密
非对称加密
使用的是非对称加密,给前端一个公钥加密之后传递到后台解密之后处理数据文件很大的用对称加密,速度快 但是不能保存敏感信息文件很小的适合用非对称加密,速度慢,但是安全性高
上传的数据安全性你是如何控制的网络传输的安全性
你在项目中遇到过那些棘手的问题
你们是怎么做压测(性能测试)的
为什么要采集日志?定位系统问题的重要手段,根据日志信息快速定位系统中的问题
采集日志的方式有哪些?常规采集:按天保存到一个日志文件ELK(比较重要)ElasticSearch,Logstash,Kibana
你们项目中日志是怎么采集的
查看日志命令
怎么快速定位瓶颈
生产问题怎么排查?
常见的技术场景!!!!
企业场景篇
所有产品共有一个工厂,如果要新增产品则需要修改代码
每个产品都提供一个工厂,项目中用的最多
多个维度的工厂需要配合生产时候使用,企业用的较少
工厂设计模式有哪些?
策略模式定义了一系列的算法,将算法封装起来,他们之间可以相互替换,算法的变换不会影响到客户系统需要动态的在几种算法中选择一种,算法封装到策略类中
案例(工厂方法+策略)让spring容器统一管理介绍业务(登录,支付,解析,促销)
什么是策略模式
缺点:较长的责任链性能容易造成影响,复杂性增加
降低耦合度增加系统可扩展责任指派灵活性责任分担
适合场景:内容审核:文本审核-图片审核-视频审核订单创建:简易参数-填充订单-算价-落库-返佣简易流程审批:组长审批-主管审批-副总裁-总裁
责任链模式的优缺点
#{}是预编译,是一个占位符,${}是字符串替换,是拼接符Mybatis处理的时候,会将sql中的#{}替换为?,调用Preparestatement来赋值,保证sql不会被注入${}是将你传过来的值之间替换进去,调用statement来赋值容易被注入
#{}和${}的区别是什么
实际上是一个map用来存放各种对象map,在启动的时候会读取配置文件的bean节点根据全限定类名反射创建对象到map里。
容器概念
没有引入IOC之前,A对象依赖于对象B,那么在初始化或者运行到某一节点时候,需要去主动创建B或者使用已经创建的B对象,使用权在自己手里引入IOC之后,A对象和B对象失去了直接联系,IOC来控制对象B需要注入到对象A的地方
控制反转
由自身管理变成了IOC容器的主动注入
谈谈你对IOC的理解
ApplicationContext是BeanFactory的子接口它提供了更完整的功能。BeanFactory采用的是延迟加载的形式来注入Bean,只有到某一时刻才会进行Bean实例化ApplicationContext是在容器启动的时候就加载所有的Bean,在启动的时候就可以发现配置错误ApplicationContext的缺点就是占用内存空间,应用程序配置较多的时候启动比较慢BeanFactory和applicaitoncontext都支持BeanPostProcesser,BeanFactoryPostProcesser使用区别在于BeanFactory需要手动注册,ApplicationContext自动注册
BeanFactory和ApplicationContext的区别?
==对比的是栈中的值,equals对比的是两个字符串的内容
==和equals的区别
类不可被继承
修饰类
修饰方法
变量一旦被赋值无法修改
修饰变量
final的作用
BootStrapClassLoader
ExtClassLoader
AppClassLoader
java类加载器有哪些?
方法不可被子类覆盖,但是它可以重载
Autowired是spring里面提供的一个注解,默认是根据类型来实现bean的依赖注入Autowired里面有一个require属性默认值是true,表示强制要求bean实例的注入如果启动的时候IOC容器里面不存在对应类型的bean启动的时候就会报错。Autowired是根据类型来实现注入的,如果一个ioc容器里面存在多个相同的bean就会报错可以使用primary的注解来解决,这个表示主要bean存在多个类型的时候优先使用primary的注解qualifer类似于条件bean根据bean的名字找到需要的目标bean
Resource注解是JDK里面提供的注解,使用方式和autowired注解的使用方式完全相同,最大的差异化就是resource可以支持Byname,ByType两种注入方式如果使用name,spring会根据名字进行依赖注入,如果使用type,spring会根据类型实现依赖注入。如果都没有配置默认情况下会根据类型进行依赖注入,默认是name匹配
Resource 和Autowired的区别是什么
由于浏览器有同源策略的一个限制,只能访问同源的资源不能访问其他源的资源目的就是不破坏同源策略的限制下能够安全的进行数据的共享和交互使用WebMvcConfigurer接口重新appCorsMapping方法来配置允许跨域的请求源
springboot如何解决跨域问题
在计算机领域里幂等性指的是方法被重复使用之后造成的影响和第一次相同,一般常见于用户的重复请求和恶意攻击导致请求多次重复执行在分布式架构中,为了避免网络导致的数据丢失通常会使用超时重复机制,但是容易导致服务端口被重复调用使用Redis里面的setnx指令,比如MQ消费的场景,避免MQ重复消费导致数据被多次修改,接收到MQ消息的同时,消息就会通过setnx写入Redis里面一旦消息被消费过就不会重复消费
幂等性是什么怎么处理
避免多线程的环境下出现歧义的问题,如果我们通过get(key)来获取value的时候返回的结果为null无法判断put(k,v)中key本身不存在或者是value为null值
ConcorrentHashMap中的key为什么不允许为null
MyISAM和Innodb区别都是mysql里面的两个存储引擎在mysql5.5之前用的是MyISAM在5.5后默认是innodb我们平时开发也用的是innodb
MyISAM和innodb数据存储的方式不同,一个是索引和数据分开,innodb存储在同一个里面innodb支持ACID特性的事务处理,MyISam只支持表锁,innodb支持表锁行锁等很多锁innodb支持外键,MyIsam不支持外键,如果大部分表需要查询操作可以用MyIsam
MyISAM和Innodb区别
TCP是可靠的基于字节流的面向连接的传输层的协议。在收发数据之前必须进行可靠的数据连接,建立连接三次握手(通信双方要发送三次请求),断开连接的四次挥手
TCP协议是什么,为什么要设置三次挥手
Cookie存储在客户端,session存储在服务器端。cookie是通过客户端的浏览器中存储数据来实现的,session在服务器端来创建会话对象来存储数据由于cookie存储在客户端所以不太安全,而且cookie的存储数据容量比session少。Session通常不支持跨域访问,但是由于session存储在服务器端,只要在客户端保存会话ID,减少网络传输的数据量
cookie和session区别
确定分片的策略可以根据业务的需求和数据特点来确定分片规则,按照用户id,时间地点
分库分表如何实现?
可以通过设置唯一的标识来实现分布式锁
基于数据库的实现
使用redission来实现分布式锁,setnx命令锁的获取
基于缓存的实现
raft协议来实现分布式锁,选举制度来保证一致性
基于分布式算法的实现
分布式锁的实现方式有哪些?
使用java里bin包下的visualVm来诊断
使用gdb工具获取进程调用栈信息,查询是否有死循环或者递归的问题
CPU飙升如何排查
首先就是启用备用的服务器,降低负载,限流的方式来稳定应用
可以通过查看日志监控系统等信息来定位问题
如果是实在恶性的bug 进行回滚操作
线上应用出现了bug怎么办
spring事务是通过声明式事务管理和编程式事务管理来实现的通过在方法上添加@Transcational注解来实现对事务的控制,提供灵活的事务传播行为
msql是根据start transcation,commit,rollback等sql语句来控制事务的开启提交和回滚,保证了并发状态下的一致性
spirng事务和mysql事务是否一样?
主要出现在多层嵌套的事务中,并且使用了不同的事务传播行为事务悬挂指的是内层事务开始时候,会挂起外层事务,如果内存事务没有正常完成或者回滚那就处于一直等待状态空回滚,内层事务回滚外层事务,即使外层事务没有出现异常
事务悬挂和空回滚
springboot通过约定大于配置的思想减少了繁琐的XML配置,SSM需要手动配置springboot开发效率更高,便于部署和运行,依赖管理更简单
springboot和ssm的区别?
StringBuffer是线程安全的使用了synchronized关键字进行同步,但是它性能比较低。如果在多线程的环境下进行操作用stringbuffer
Stringbuilder因为没有同步处理所以性能比较高,相对的线程不是安全的,如果在单线程的环境下运行就用stringbuilder
StringBuffer和Stringbuilde的区别?
使用trycatch来异常捕获处理,或者是用throws关键字来抛出异常,使用finally块。或者是自定义异常类
工作中怎么处理异常?
volatile可以保证指令重排和可见性。指令重排使用的是读写屏障防止越过,可见性是操作共享变量的同时对其他线程可见synchronized可以保证原子性,通过互斥锁的方法来实现原子性和线程安全。volatile性能比较好
volatile和synchronized 的区别?
二级缓存适合相对稳定的数据,有可能造成数据不一致的问题。默认使用的是perpetualCache作为缓存实现用来减少重复查询的开销
mybatis的二级缓存
广泛应用于物联网中:轻量级,节约带宽,和灵活。基于TCP/IP的协议栈来传输
mqtt是轻量级发布的订阅协议,用于低带宽,高延迟,不可靠的网络环境进行消息传输它支持三种不同消息的传递数量等级QoS0:最多一次,消费者发布消息后不会收到确认,可能会造成丢失QoS1:最少一次,消息发布者会收到消息确认,确保消息最少被重复传输一次,容易造成数据重复问题QoS2:只有一次,消息分布着会收到消息确认,确保消息只被传输一次,可能会有更高的延迟和开销
单点登录这个目的就是用户只要登录一次就可以在多个系统和应用之间无缝访问
单点登录和实现流程?
第一点就是使用同步锁或者分布式锁来确保原子性,第二点就是高并发的情况下可以把库存数据预热到Redis缓存中第三点就是如果某个商品访问量较大,可以对库存进行拆分,降低访问的压力之后对单个sku的数据加锁
如何防止超卖问题?
实例化对象的时候,JVM首先会检查目标对象是否已经被加载或实例化,如果没有jvm会加载目标类并且完成初始化。类加载是通过类加载器来实现的主要是把一个类加载到内存中之后对静态变量,成员变量,静态代码块进行初始化,目标类被初始化以后就可以去常量池找类元信息。目标对象的大小在类加载完成之后就已经确定了,需要为新创建的对象根据目标对象的大小在堆内存里面去创建空间。内存分配的方式有两种,第一种是指针碰撞,第二种是空闲列表,jvm会根据内次是否规整来决定分配方法,之后把普通成员变量初始化为0值保证对象里面的实例字段不用初始化就可以直接使用,之后jvm会对目标对象的对象头进行设置类员信息,GC分代年龄,hashcod等。接下来就是执行目标对象的init方法,初始化成员变量的值,执行构造块,最后调用目标对象的构造方法
java对象的创建过程
java基础题
1.我们首先进行了需求分析和规划(包括项目有关的所有受益者,农民,消费者,物流服务商等)2.确定了必要的功能列表(产品展示,订单管理,支付,物流追踪,用户管理等内容)
1.后端使用java,springboot,springmvc还有mysql来编写业务逻辑,API接口和数据持久化的逻辑2.创建了所需要的表,视图等3.集成第三方服务,支付网关,短信服务,物流api4.我们还进行了单元测试,集成测试和系统测试保证正常工作
之后是部署和上线,部署后端到阿里云,进行负载测试
说一下你们的服务电商平台的整个项目流程
我们是小型的服务平台 有1台服务器
你们的服务平台一般有多少数据量?
我们的网站有五万的用户,平均日活为0.4.也就是日活为2万。集中时间段为4个小时,平均点击量为三,qps为4.
你们那个平台的线上运行情况如何?
我们一般用在了订单管理,多个用户购买同一商品的时候保证一致性防止超卖,第二个地方就在库存管理,避免数据不一致的问题。第三点用的是农产品价格更新的时候,不被干扰防止显示错误价格。
你们项目中分布式锁用在了什么地方
缓存管理:将常用的数据存储在缓存中,将频繁访问公共资源的数据(图片,文件,配置信息)
会话管理:用户的登录状态,权限信息等
计数器:对资源的访问次数,下载次数进行统计,方便计数管理
发布/订阅:实现消息发布和订阅功能,实现消息的发布和订阅机制
你负责的项目中redis用在了什么方面?
用的swagger做的本地测试,
用JenKins做单元测试
你的项目是怎么做的测试
我走的时候项目是交付了,但是具体的部署服务器是由甲方的运维部署的,我不知道;
因为我做的是乡村治理综合平台的公共管理模块相关的内容,我们用的是敏捷开发模式,约定是六个月上线。用了半个月的时间建表和分析需求,后面每个月会做版本会做迭代开发,第四个月交付给客户,有意见及时修改
我们项目组有测试环境用的是公司租了一台Linux服务器,每个迭代周期将开发好的功能打包上传(maven包打包成jar包)到测试环境及时解决,用swagger进行本地测试,用Jenkins进行单元测试,用git来管理代码使用swagger用于测试Restful,生成可读性的API文档,提供给其他开发人员或测试团队进行测试。
项目开发好之后,我们项目经理和运维一起把项目部署到对方指定的服务器上,对方用的是云服务器进行部署的,具体的细节我不太清楚。
问项目是否上线
用的windows写的,使用的Linux服务器部署的
你的项目中用了什么系统开发的
故障报修中通知机制:为了保证实时性使用RabbitMq来实时通知和更新工单状态,用到了Reddision分布式锁来保证多个操作的正确性和一致性
监控告警这个子模块中,我当时碰到了多次触发相同告警情况,设置了冷却时间,还有告警的阈值,我们也有一个相关的告警表:设备ID,类型,触发时间等内容,如果相同的告警就被判定重复告警
用户参与反馈遇到了一些用户账户的安全性问题,用了springsecurity认证框架来实现用户登录。
你在你负责的模块项目开发中遇到的难题
我们项目在部署后,会对MySQL数据库进行监控,一旦超过5s我们就会收到告警通知,遇到长SQL以后,我们会用执行计划(Execute Plan)分析该sql,len和key_len看是否命中索引,extra判断是否有回表,type看是否有优化空间
最常见的原因就是索引,没使用联合索引
使用了MyCat分库分表 根据业务去拆分表
刚开始我不熟悉数据库性能调优的问题,但后来熟悉了。
用vi命令打开日志文件,再用根据错误关键字和时间,搜索找到上下文,再根据该日志的线程ID去看在该日志文件的其它 日志
请求类型应该是post但是我发的是get,最后加了异常处理机制
刚开始我只知道在windows里开发,不熟悉linux操作,尤其是在linux里看日志的操作
问监控怎么做:这套监控是运维或项目经理搭建的
你在项目开发中遇到的棘手的问题?
首先就是安全性问题,需要涉及到数据的跨网络传输,为了数据被拦截和篡改,使用https通信协议和数据签名
影响用户体验,和业务的正常流程
接口的稳定性和可靠性
并发量限制,评估是否满足当前业务需求
存在费用限制,也要评估费用问题
接口是否存在访问限制或费用
对接第三方接口要考虑什么?正常情况下是按照第三方的接口文档去写的有些的会提供工具包
农业电商服务平台
实战项目篇
它俩都是开源的业务流程管理平台,帮助自动化和优化业务流程
如何使用?
业务之间的各个步骤以及规则进行抽象和概括性的描述,以特定的语言为流程建模,并让计算机进行计算和推动。业务建模用的是BPM2.0的国际通用语言缺点就是:如果流程做变更就需要做大量的更改
什么是工作流?
使用专门的建模语言BPMN2.0进行定义,流程由flowable进行监管
一,首先用BPMN来定义流程二,使用flowable框架来实现流程
Flowable和Activiti是两个流程引擎框架,它们都是基于BPMN 2.0标准的开源工作流引擎。以下是它们之间的一些主要区别:项目背景:Activiti是由Alfresco公司开发的一个成熟的工作流引擎,于2013年成为Apache软件基金会的顶级项目。而Flowable则是Activiti的一个分支,由Activiti的核心开发团队在2016年创建的,目的是推进工作流引擎的发展和创新。社区支持:Activiti拥有一个成熟的开源社区,并有广泛的用户群体。由于历史更长,Activiti的社区资源和文档较多。而Flowable虽然相对年轻,但也拥有一个活跃的开源社区,不断有新功能和改进推出。版本兼容性:Flowable保持与Activiti的兼容性,可以无缝地迁移到Flowable,而Activiti并不一定能无缝迁移到Flowable。Flowable在API和功能上进行了一些改进和扩展,但对于使用Activiti开发的项目,可以比较容易地迁移到Flowable。功能差异:Flowable相对于Activiti在功能上进行了一些增强和扩展,例如添加了CMMN(Case Management Model and Notation)和DMN(Decision Model and Notation)的支持,提供了更丰富的任务管理和表单处理功能。Flowable还引入了Flowable UI应用程序,提供了更现代化和可定制的用户界面。
Flowable流程引擎(将业务中的复杂的业务流程抽取出来)
flowable和actitivi
数据量大,表查询频繁的时候需要用索引
索引的数量不宜过多
常作为查询,排序分组字段
索引优化
避免使用select *
尽量多使用Inner Join
使用聚合查询的时候尽量使用union all 而不用union
SQL语句的优化:通过explain进行分析查询
表设计结构的优化:根据业务需求可以进行 垂直分库分表或者是水平分库分表
mysql的优化
创建线程对象,
启动线程
线程执行
线程的使用
用哈希表来存储键值对
HashMap
通过红黑树来存储键值对。
TreeMap:
维护了双向链表,,除哈希表来存储键值对之外还有指向前后的两个指针
LinkHashMap;
详细说说map集合的存储方式
Arraylist:适合查询,不适合添加或者删除元素
LinkLis:链表适合添加删除元素,不适合查询t
List集合:有序可重复的
HashSet:基于hash表实现的,无序的。查找添加删除等操作效率高 O(1)不允许重复操作,线程不安全
TreeSet:基于红黑树来实现的,有序,不允许重复操作,线程不安全 效率略低hashset
Set集合:无序不重复的
Collection 单列集合
HashMap:线程不安全的,他在单线程的环境下性能较好,适合在只有一个线程写入多个线程读取的情况下
ConcurrentHashMap 线程安全的,采用了分段锁的机制并发比较好
TreeMap红黑树
Map是双列集合
继承Tread类:重写run方法
实现Runnable接口:提高代码的可读性和可维护性
实现Callable接口:可以返回结果和抛出异常
实现线程的方法
常用的集合有哪几种?
1,int的初始值为0,interger的初始值为null2,int是java基本的数据类型,integer是包装类,可以作为泛用类型也可以做方法对象
int和Interger的区别:
Jquery的取值是通过$().val()的形式,需要添加额外的库
javaScript的取值是通过document.的形式来取值的,他不需要额外的库更加原生
jquery和javascript取值
jquery和JavaScript之间的联系和区别
担任的角色,就职期间担任了后端开发的模块,被分配到了公共资源 管理相关功能的组。
用户首先发现故障或者需要维修的信息之后,通过平台提交报修请求《包括相关信息,故障描述,报修人的联系方式,报修地点等
报修请求被接收后,系统会自动生成工单,工单内容包括报修问题的详细描述报修人信息,报修时间等
将工单会传到维修人员相关的界面上,维修人员会接到工单并进行处理
维修人员处理完毕之后会更新工单状态,记录相关的处理信息。
解决之后工单被标记已解决,工单关闭
负责的东西,我负责了故障报修和工单管理模块,用户参与和反馈模块,监控设备告警功能的实现相关的业务。
1、一个故障表(记录各种故障)2、设备表(记录各种设备)3、设备故障表(记录什么设备出现了什么故障以及上报信息)4、设备故障日志表(统计所有的设备故障上报信息)5、用户表;6、用户保修表;7、审核记录表(报修后需要审核),还有一种记录枚举值的表
相关的表
你遇到的难点处理:1.刚开始我不熟悉测试和部署等流程后来慢慢熟悉了。我们用的是maven来管理项目,用jenkins来进行部署 除了写java代码之外我还进行了单元测试和联调,最后将java代码打包jar包部署到Linux服务器上2.数据库的性能调优,项目部署之后会对Mysql数据库进行监控(监控是项目经理搭建的) 一旦SQL语句执行时间超过五六秒就会有告警邮件之后我会通过Explain进行性能分析sql 通过key,key_len 查看是否命中索引,type看是否有回表,之后extra看是否有优化空间。常见的问题就是索引相关的,有的时候是索引数据过多有的时候是没进行联合索引。3.开始只知道在window里开发,不熟悉Linux操作,尤其是看日志文件,有时候会出现服务器错误,我登录Linux服务器上 使用vi命令查看日志文件,根据该日志ID去看其他日志,如果有其他业务我用traceID去查找有的时候是请求类型错误POST请求发GET,最后加异常处理机制
通过logback输出日志的方式:通过LoggerFactory.getLogger()方法获取Logger对象
linux搜索关键字用grep,grep -r 还有使用cat命令查看文件内容
说一说你的项目:从担任的角色,负责的东西,难点处理三个方面来说
mysql的百万数据如何快速查找
哈尔滨移动面试题
Java
0 条评论
回复 删除
下一页