面试题汇总
2024-04-18 11:41:27 14 举报
AI智能生成
java面试题
作者其他创作
大纲/内容
Redis:AP思想保证高可用性
CP思想的是Zookeeper
CP思想的是Zookeeper
使用场景
缓存
缓存穿透,缓存击穿,缓存雪崩
什么是缓存穿透,怎么解决
发生的条件:查询一个不存在的数据,MySQL查询不到数据也不会直接写入缓存,导致每次查询都会请求到数据库
如何解决缓存穿透
缓存空数据,将查询的数据设置为空,仍把这个空结果进行缓存
优点是简单
数据丢失,容易造成不一致问题
布隆过滤器:布隆过滤器通过bitmap位图来检索一个元素是否在一个集合中。作用是拦截不存在的数据
使用:在缓存预热的时候往布隆过滤器里添加数据,会直接查询布隆过滤器
优点:占用内存较少,没有多余的key
缺点是:实现起来比较复杂
布隆过滤器使用Redission来实现布隆过滤器:底层是初始化一个比较大的数组里面存放
0或者1,放置一个key进行3次的hash计算,通过去模的方式将数组下标把原来的数组改
成1。这样的话3个数组位置就能标明一个key存在
0或者1,放置一个key进行3次的hash计算,通过去模的方式将数组下标把原来的数组改
成1。这样的话3个数组位置就能标明一个key存在
布隆过滤器也是有一定的缺点的,容易造成误判。我们可以设置误判率,误判率百分之5以内
不至于在高并发下面压倒数据库
不至于在高并发下面压倒数据库
什么是缓存击穿,怎么解决
发生的条件:给某一个key设置了过期时间,当这个key过期的时候恰好有大量的并发请求打在了这个key上
如何解决缓存击穿
热点key不过期
高可用性
高可用,性能优
设置互斥锁
互斥锁的流程:线程一查询缓存未命中,这个线程会获取互斥锁,之后去查询数据库
重建缓存数据,再将数据写入缓存中,最后释放锁。
线程2查询缓存未命中时,因为互斥锁的缘故它会休眠一会重试直到线程一释放锁
重建缓存数据,再将数据写入缓存中,最后释放锁。
线程2查询缓存未命中时,因为互斥锁的缘故它会休眠一会重试直到线程一释放锁
强一致性,性能差
什么是缓存雪崩,怎么解决
发生的条件:缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
- 解决方案:设置不同的过期时间
- 解决方案:如果是服务器宕机问题会使用Redis集群提高服务可用性(哨兵模式,集群模式)
- 解决方案:给缓存业务添加降级限流策略(nginx,springcloud gateway)
- 解决方案:给业务设置多级缓存(Guava或Caffeine)
面试回答:设置缓存时使用了相同的过期时间,导致缓存在某一时刻同时失效导致大量的数据转发到DB,
与缓存击穿的区别是缓存雪崩是大量的Key,缓存击穿是某一个key缓存
解决方案是将:缓存失效时间分散开在原有的基础上增加一个随机值比如1-5分钟随机
与缓存击穿的区别是缓存雪崩是大量的Key,缓存击穿是某一个key缓存
解决方案是将:缓存失效时间分散开在原有的基础上增加一个随机值比如1-5分钟随机
双写一致性,持久化
Redis数据的持久化策略有哪些
RDB
RDB概念:将内存中的所有数据记录到磁盘中,当Redis故障重启之后从磁盘中读取快照文件,恢复数据
RDB执行原理:bgsave开始会fork主进程得到子进程,子进程共享主进程的数据,完成fork后会读取内存数据并写入RDB文件
fork采用的是copy-on-write方式,写操作的时候会写数据的复制层之后去读复制层
fork采用的是copy-on-write方式,写操作的时候会写数据的复制层之后去读复制层
AOF
AOF执行原理:记录每一次执行的命令,数据完整性和文件大小相对较大,宕机恢复速度慢,安全性比较高
Redis双写问题
面试回答:Redis作为缓存如何与Mysql数据库进行同步呢?
(双写一致性):修改了数据库的数据也要更新缓存的数据缓存
和数据库保持一致
(双写一致性):修改了数据库的数据也要更新缓存的数据缓存
和数据库保持一致
介绍自己简历上的业务,我们当时是把文章的热点数据存入到了缓存中,
虽然是热点数据,但是实时要求性并没有那么高,所以,我们当时采用
的是异步的方案同步的数据
虽然是热点数据,但是实时要求性并没有那么高,所以,我们当时采用
的是异步的方案同步的数据
1.使用MQ消息中间键,更新数据之后通知缓存删除
2.利用Canal不需要修改业务代码,伪装成mysql的一个从节点通过读取binlog来数据更新缓存
我们当时是把抢券的库存存入到了缓存中,这个需要实时的进行数据同步
,为了保证数据的强一致,我们当时采用的是redisson提供的读写锁来保
证数据的同步
,为了保证数据的强一致,我们当时采用的是redisson提供的读写锁来保
证数据的同步
为了保证强一致性采用Redission读写锁
1.共享锁:共享锁:读锁readLock,加锁之后,其他线程可以共享读操作
2.排他锁:排他锁使用的也是setnx独占锁writeLock也叫,加锁之后,阻塞其他线程读写操作
1.共享锁:共享锁:读锁readLock,加锁之后,其他线程可以共享读操作
2.排他锁:排他锁使用的也是setnx独占锁writeLock也叫,加锁之后,阻塞其他线程读写操作
双写一致性:
读操作:缓存命中直接返回,缓存未命中读取mysql中的数据之后写入缓存设置过期时间
写操作:
延迟双删:先删除缓存再删除数据库因为线程是切换的所以容易造成脏数据问题
为什么要双删?
降低脏数据的出现
为什么要延迟?
数据库是主从模式,读写分离的所以要延迟一会
读操作:缓存命中直接返回,缓存未命中读取mysql中的数据之后写入缓存设置过期时间
写操作:
延迟双删:先删除缓存再删除数据库因为线程是切换的所以容易造成脏数据问题
为什么要双删?
降低脏数据的出现
为什么要延迟?
数据库是主从模式,读写分离的所以要延迟一会
双写一致性如何保证强一致性?(一致性要求高的)
加分布式锁
因为缓存中的数据是读多写少所以可以使用读写锁
强一致性使用读写锁但是性能低
最终一致性
异步通知:rabbitmq,rocketmq,kafka
Canal
延迟双删的缺点是:延迟双删先删除缓存中的数据,之后更新数据库,再之后删除缓存中的 数据 但是不好设置延迟时间
而且也存在脏读问题
而且也存在脏读问题
数据过期,淘汰策略
Redis数据过期策略有哪些
惰性删除
设置Key过期时间后不去管它,等到再次访问时判断是否过期并删除
优点:对CPU友好,不用浪费时间进行检查
缺点:如果不去访问这个Key那么Key会用不释放
定期删除
每隔一段时间会定期对Key进行检查,并删除
SLOW模式
SLOW模式是定时任务,每秒执行十次(可以手动配置)清理耗时不超过25ms'
Fast模式
Fast模式执行的频率不固定,两次间隔不低于2ms,每次耗时不超过1ms
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算法进行淘汰
分布式锁
setnx,redission
分布式锁如何实现
Redis分布式锁主要是运用了setnx命令,setnx是Set if not exist的简写
Redis实现分布式锁——可重入
Field是持有锁线程的唯一标识
value当前线程重入次数
总体的实现流程是:如果使用了同一把锁那么value值+1,如果释放了锁那么value-1
Field是持有锁线程的唯一标识
value当前线程重入次数
总体的实现流程是:如果使用了同一把锁那么value值+1,如果释放了锁那么value-1
Redis实现分布式锁——主从数据一致
红锁(Red Lock)不在一个Redis实例中创建锁,而在多个Redis实例中创建锁
实现复杂 性能差 运维繁琐
红锁(Red Lock)不在一个Redis实例中创建锁,而在多个Redis实例中创建锁
实现复杂 性能差 运维繁琐
Redis分布式锁如何合理的控制有效时常
根据业务的执行时间预估
给锁续期
看门狗技术
假如while循环的好处是:高并发下增加分布式锁的实用性
假如while循环的好处是:高并发下增加分布式锁的实用性
加锁,和设置过期时间都是基于lua脚本完成(lua调用Redis命令,来保证多条命令执行的原子性)
分布式锁通常情况下的使用场景:集群情况下的定时,抢单,幂等性场景
注意:为什么synchoinezd锁不适合抢卷场景?
因为synchoinzed锁是本地锁,只能解决同一个线程下不能解决集群
因为synchoinzed锁是本地锁,只能解决同一个线程下不能解决集群
计数器
incr和decr来进行增加和减少数值指令
保存token
String字符串来保存键值对,使用expire来设置过期时间
消息队列
list来实现简单的消息队列
延迟队列
使用sortset来实现延迟队列
其他相关问题
集群相关
主从
单点Redis并发能力有上限的如果实现Redis并发能力,需要用到主从集群,实现读写分离
全量同步
- 从节点发送请求到主节点请求同步数据主节点Master判断是不是
第一次请求如果不是则会全量同步 - 主节点master会执行bgsave生成一个RDB文件发送给从节点进行执行
- 主节点master在记录RDB期间接收的其他命令会记录到reportbacklog
日志文件中,再将日志文件发送给从节点去执行
增量同步
(slave从机重启或后期数据发生变化)
(slave从机重启或后期数据发生变化)
1.从节点slave发起同步请求,主节点判断是不是第一次请求
并且获取到从节点slave发送过来的offset值
2.主节点master从日志文件中获取offset之后的数据同步到
从节点
并且获取到从节点slave发送过来的offset值
2.主节点master从日志文件中获取offset之后的数据同步到
从节点
哨兵
哨兵模式
(提供了主从集群的自动故障恢复)Sentinel
(提供了主从集群的自动故障恢复)Sentinel
监控
自动故障恢复
通知
集群
集群中出现的问题
海量数据存储
高并发写的问题
事务
Redis为什么那么快
Redis是纯内存,执行速度非常快
采用单线程的避免不必要的上下文切换竞争条件
Redis运用的是IO多路复用技术,非阻塞式IO
Redis的网络模型是 IO多路复用+事件派发的机制
Mysql
Mysql的优化
定位慢
聚合查询
多表查询
数据量过大查询
深度分页查询
Mysql执行计划
索引
存储引擎
Sql底层的数据结构
聚簇和非聚簇索引
覆盖索引
子主题
索引创建的原则
数据量较大,查询频繁——单表超过10万
尽量选择区分度较高的列作为索引,尽量建立唯一索引,区分度越高效率越高
常作为查询条件Where,OrderBy,GroupBy
如果字段长度较长,根据字段特点建立索引
尽量使用联合索引,联合索引很多时候可以用覆盖索引避免回表,提高效率
控制索引的数量,太多维护比较麻烦
创建表时,使用NOT NULL约束
索引失效的场景
违反了最左前缀法则
正常情况下
违反最左前缀法则
范围查询右边的列,不能使用索引
索引列上进行运算操作
字符串不加‘ ‘ 导致失效
模糊查询可能导致索引失效
Sql优化经验
其他面试题
事务相关
事务特性
隔离级别
MVCC
Multi-Vesion-Concurrentcy-Control多版本并发控制,维护一个事务的多版本,使得读写没有冲突
隐藏字段
undolog日志
回滚日志:当使用insert,update,delete产生便于回滚的数据日志
当insert产生时,undolog日志只会在回滚时需要,事务提交后立刻删除
update,delete回滚时需要,MVCC也需要不会被立刻删除
当insert产生时,undolog日志只会在回滚时需要,事务提交后立刻删除
update,delete回滚时需要,MVCC也需要不会被立刻删除
readView
是快照读SQL提取mvcc的数据依据,记录并维护系统当前的活跃事务id
当前读:读取的最新版本记录,保证其他并发事务不能修改对读取的数据进行加锁
快照读:读取数据的可见版本,也有可能是历史数据,不加锁的非阻塞
rc:读已提交每次select都会生成快照读
rr:仅在第一次的时候生成readview其他时都会复用ReadView
当前读:读取的最新版本记录,保证其他并发事务不能修改对读取的数据进行加锁
快照读:读取数据的可见版本,也有可能是历史数据,不加锁的非阻塞
rc:读已提交每次select都会生成快照读
rr:仅在第一次的时候生成readview其他时都会复用ReadView
RC
RC级别下获取历史版本记录
RR
主从同步
核心是二进制文件也叫BinLog日志记录所有DDL(数据定义语言)语句和DML(数据操作语言)语句
面试官问题:主从同步的机制
主库提交事务之后,会将数据变更存储到二进制的Binlog文件中
从库读取主库的二进制文件binlog,写入从库的中级日志RelayLog
从库重做中继日志的事件,改变反应它自己的数据
从库读取主库的二进制文件binlog,写入从库的中级日志RelayLog
从库重做中继日志的事件,改变反应它自己的数据
分库分表(解决存储压力)
分库分表的时机:随着项目业务数据增多,业务发展迅速 达到一千万或20G以后
优化解决不了性能问题
IO瓶颈,CPU瓶颈
框架篇
Spring
Spring
Bean安全问题
AOP
事务原理
AOP是面向切面编程,将那些与业务无关但是对多个对象产生影响的公共行为和逻辑
,抽取并且封装成一个可重用的模块这个模块叫做切面Aspect。减少重复代码,
降低耦合度,提高代码复用性
,抽取并且封装成一个可重用的模块这个模块叫做切面Aspect。减少重复代码,
降低耦合度,提高代码复用性
AOP场景
记录操作日志
子主题
缓存处理:AOP切面拦截需要添加缓存的业务方法
Spring中内置的事务处理
事务失效
异常捕获处理失效
抛出检查异常可能失效
非Public方法导致失效
Bean的生命周期
流程图
构造函数
构造函数必须与类名相同且不能有返回值
每个类可以有多个构造函数,如果没有写默认无参
伴随new去执行,不能自己调用由系统调用且一次
不能被继承,可以被重载
依赖注入
或者@AutoWired
Aware'接口
三个aware实现方法
BeanPostProcesser-前置
子主题
执行初始化方法
自定义的初始化
Initializtion初始化方法
BeanPostProcesser-后置(用于增强)
AOP增强使用的动态代理——JDK和CGLIB
销毁
子主题
循环依赖
A依赖于B ,B依赖于A
默认情况下循环依赖会导致死循环问题
解决方法:三级缓存
一级缓存:没有完全走完生命周期A,B都为半成品无法解决循环依赖
二级缓存:二级缓存可以解决一般情况下的循环依赖,但是无法解决代理对象(增强)的循环依赖
三级缓存:能够解决大部分的循环依赖
实例化过程的循环依赖
SpringMVC
执行流程
视图阶段(JSP)
1.首先浏览器发送请求之后会打到前端控制器中
前端控制器————调度中心
2.处理器映射器的主要作用是执行方法
(前端控制器向处理器映射器查询handler方法
(handler是getByid这类的方法)并执行)
继续返回处理器执行链(拦截器和handler一起封装)给前端控制器
3.假如没有拦截器会之间找处理器适配器去请求处理某一个方法
之后返回ModleAndView给前端控制器
处理器适配器(处理参数User user这些,返回值返回User返回R等什么的)
4.最后前端控制器去找视图解析器,逻辑视图变成真正视图返回JSP
前端控制器————调度中心
2.处理器映射器的主要作用是执行方法
(前端控制器向处理器映射器查询handler方法
(handler是getByid这类的方法)并执行)
继续返回处理器执行链(拦截器和handler一起封装)给前端控制器
3.假如没有拦截器会之间找处理器适配器去请求处理某一个方法
之后返回ModleAndView给前端控制器
处理器适配器(处理参数User user这些,返回值返回User返回R等什么的)
4.最后前端控制器去找视图解析器,逻辑视图变成真正视图返回JSP
前后端分离开发(接口开发,异步请求)
返回结果通过@ResponseBody之间转成JSON并且响应,跳过了视图解析器
SpringBoot
自动配置原理
子主题
Spring/SpringMVC/SpringBoot常用注解
Spring
Spring
SpirngMvc
SpringMVC
SrpingBoot
SrpingBoot
MyBatis
执行流程
子主题
Myabatis的延迟加载
使用了CGLIB创建目标对象的代理对象
当调用方法时(比如查询OrderList)进入拦截器ivoke发现,判断orderlist是否为空
如果使用延迟加载那么orderlist肯定为空,最后执行sql查询订单并封装再获取就拿到数据了
当调用方法时(比如查询OrderList)进入拦截器ivoke发现,判断orderlist是否为空
如果使用延迟加载那么orderlist肯定为空,最后执行sql查询订单并封装再获取就拿到数据了
延迟加载
支持的一二级缓存
一级缓存:Perpetual 的HashMap本地缓存,作用域为Session,默认打开一级缓存
注意:1/2级缓存只要实现增删改操作都会被清空clear
只有会话提交关闭之后一级才可以转移二级
二级缓存要实现Serialiable
只有会话提交关闭之后一级才可以转移二级
二级缓存要实现Serialiable
二级缓存:基于namespace和mapper 的作用域起作用的,不依赖于session 默认也是perpetual Hash来存储
默认的关闭的
默认的关闭的
二级缓存开启
微服务篇
SpringCloud
服务注册
Nacos
Eureka
负载均衡
Ribbon的负载均衡策略
自定义负载均衡策略
熔断和降级
熔断
监控
Skywalking
业务相关
限流
限流的实现方式
Tomcat:默认最大连接数是200
Nginx,漏桶算法:本质上就是以固定的流量进行处理
网关,令牌桶算法
自定义拦截器
分布式事务
分布式理论CAP,BASE
分布式事务解决方案
seata
TC(Coordination):事务协调者,维护全局和分支事务的状态,协调全局事务提交或回滚
TM(Manager):事务管理者:定义和开启全局事务的范围,提交和回滚全局事务
RM(Resource Manage):资源管理器:管理分支事务处理资源,于TC交谈记录分支事务于报告分支事务的状态
并驱动分支事务提交或者回滚
并驱动分支事务提交或者回滚
分布式服务接口幂等
幂等:多次调用方法或者接口不会改变业务的状态,可以保证重复调用的结果和单词调用的结果一致
需要幂等的场景:
由于网络波动导致的用户重复点击
MQ消息重复
应用使用失败或超时重试
由于网络波动导致的用户重复点击
MQ消息重复
应用使用失败或超时重试
GET:方式 查询操作 天然的幂等
POST:新增操作不是幂等
delete:是幂等的 删除之后就没了
PUT:如果以绝对值更新是幂等,如果增量更新不是幂等
POST:新增操作不是幂等
delete:是幂等的 删除之后就没了
PUT:如果以绝对值更新是幂等,如果增量更新不是幂等
如果保证新增的幂等?
数据库的唯一索引
token+Redis保证新增和修改
分布式锁
分布式任务调度
XXL-JOB
消息中间件
RabbitMQ常见问题
RabbitMQ的使用场景
异步发送(验证码,短信,邮件)
MYSQL和Redis,ES之间的同步
分布式事务
MYSQL和Redis,ES之间的同步
分布式事务
消息不丢失:有三种情况会导致丢失
消息没到交换机
队列中的消息丢失
消费者没收到消息
消息没到交换机
队列中的消息丢失
消费者没收到消息
消息没到交换机:通过Publisher Confirm机制来避免消息发送到MQ的过程中丢失
当消息发送到MQ之后会返回结果给消费者,表示消息处理成功
当消息发送到MQ之后会返回结果给消费者,表示消息处理成功
重发
记录日志
保存数据库定时重发,之后删除数据库中的数据
MQ宕机:MQ默认存储在内存中,可以设置持久化功能保证消息不丢失
消费者确认:处理消息之后可以向MQ发送ACK回执,MQ收到ACK回执之后会删除数据
消息重复队列
消息延迟堆积
惰性队列:将消息存储到磁盘中,而非缓存中
当消费者消费消息时候才会从磁盘中读取
支持数百万条的数据
当消费者消费消息时候才会从磁盘中读取
支持数百万条的数据
消息可靠性
延迟队列
什么是延迟队列?
进入队列的消息会被延迟消费队列
超时订单,限时优惠,和定时发布
超时订单,限时优惠,和定时发布
延迟队列和死性交换机的区别?
延迟队列=死信交换机+TTL存活时间
死信交换机
什么是死信? 消息不会被消费直接丢弃掉
不会被消费掉
不会被消费掉
过期消息,超时无人消费
投递的队列消息堆积满了,最早的消息可能会死信
basic.reject和basic.nack声明失败。消息的Requene消息设置为false
什么是TTL?
TIme-To-Live,如果队列中的消息TTL结束仍然没消费会变成死信,TTL分两种情况
消息所在队列设置存活时间
消息本身设置存活时间
注:以短的为准
消息所在队列设置存活时间
消息本身设置存活时间
注:以短的为准
高可用机制
生产环境下使用集群来保证高可用
普通集群,镜像集群,仲裁队列
普通集群
镜像集群:本质是主从模式
仲裁队列
Kafka
消息不丢失
发送消息到broker丢失:
消息在broker中存储丢失
消费者从broker接收消息时候丢失
消息顺序性
保障消息在同一分区下,才能保障消息的顺序性
消息重复队列
高可用机制
集群模式
分区备份机制
为什么不能多设置几个ISR?
因为ISR是同步保存的数据 性能会低于异步保存的数据
因为ISR是同步保存的数据 性能会低于异步保存的数据
高性能设计
消息分区
不受单台服务器限制,处理更多数据
顺序读写
磁盘顺序读写提升效率
页缓存
数据缓存到内存
零拷贝
减少上下文切换
消息压缩
减少磁盘IO和网络IO
分批发送
打包发送减少开销
数据存储和清理
文件存储机制
数据清理机制
集合相关问题
Collection
单列集合
单列集合
List有序,可重复
Vector数组结构,线程安全
ArrayList 数组结构,非线程安全
LinkedList 链表结构,非线程安全
Set 无序,唯一
HashSet哈希表结构——LinkHashSet 哈希表和链表结构
TreeSet红黑树结构
Map
双列集合
双列集合
HashTable 哈希表结构 线程安全——Properties
HashMap 哈希表结构 非线程安全——LinkHashMap 哈希表和链表结构
ConcurrentHashMap哈希表结构线程安全
TreeMap 红黑树结构
数据结构相关
时间复杂度相关
1
2
3
4
空间复杂度相关
List相关面试题
索引为什么从0开始1开始不行吗?
根据数组索引获取元素的时候,会用索引和索引公式来计算内存对应的元素数据
:数组的首地址+索引*存储类型的大小,如果用1开始会做减法
:数组的首地址+索引*存储类型的大小,如果用1开始会做减法
ArrayList底层的实现原理?
ArrayList是基于底层动态数组实现的
1.arraylist初始容量为0第一次添加数据的时候初始容量为10
2.arraylist进行扩容的时候是原容量的1.5倍,每次扩容都需要拷贝数组
1.arraylist初始容量为0第一次添加数据的时候初始容量为10
2.arraylist进行扩容的时候是原容量的1.5倍,每次扩容都需要拷贝数组
ArrayList list=new Arraylist(10)扩容了几次?
只是声明和实例了一个arraylist 并没有扩容
如何实现数组与list之间转换?
数组转list,用的是Arrays工具类中的aslist方法
list转数组,用的是list中的toArray方法
list转数组,用的是list中的toArray方法
把list转数组后,数组受到影响吗?
把数组转list,list受到影响吗?
把数组转list,list受到影响吗?
Arraylist.aslist转换list之后,修改数组内容会受到影响,底层使用的是arrays类中的内部类arraylist来构造集合
传入的集合进行包装而已
传入的集合进行包装而已
list用了toarray转数组之后修改内容不会受到影响,他是进行了数组的拷贝和原来没啥关系
ArrayList和LinkList的区别?!
单向链表只有一个方向,节点只有有一个后继指针next
双向链表有两个方向,有后继指针和前驱指针
单向链表只有一个方向,节点只有有一个后继指针next
双向链表有两个方向,有后继指针和前驱指针
1.arraylist是动态数组的数据结构实现
linklist是双向链表的数据结构实现
2.arraylist可以通过索引查询 查询效率高 但是新增删除效率低,连续的节约内存
linklist需要遍历查询 效率低,linklist新增删除效率低,存储数据两个指针 内存比较多
linklist是双向链表的数据结构实现
2.arraylist可以通过索引查询 查询效率高 但是新增删除效率低,连续的节约内存
linklist需要遍历查询 效率低,linklist新增删除效率低,存储数据两个指针 内存比较多
如何保证linklist和arraylist线程安全?
1.在方法内使用,局部变量是线程安全的
2.使用线程安全的arraylist和linklist——底层加synchronized锁
HashMap相关面试题
什么是二叉树?
每个节点最多有两个叉,左子节点和右子节点
什么是二叉搜索树?
又叫二叉搜索树,也叫二叉查找树,左子树节点的值要小于这个节点的值,右子树节点的值要大于这个节点的值
红黑树
红黑树是一种自平衡的二叉搜索树
查找添加删除都是 LogN
查找添加删除都是 LogN
散列表
什么是散列表?
散列表又称哈希表,根据key直接访问value数据结构,由数组演化过来的,利用了数组支持下标随机访问的特性
散列冲突
散列冲突又称哈希冲突,哈希碰撞。多个key映射到同一数组下标地址
散列冲突——链表法
HASHMap
并发编程篇(多线程相关面试题)
线程的基础知识
线程与进程的区别
并行与并发的区别
单核CPUI:串行执行:线程轮流使用CPU的做法叫并发
多核CPU
线程创建的方式有哪些
继承Thread类
实现Runnable接口
实现Callable接口
线程池创建线程
runnable和callable有什么区别
线程的run()和start()有什么区别
run():普通方法可以执行多次
start():不能开启多次只能开启一次
线程包括哪些状态,状态是如何变化的
线程状态
状态
new——runnable——desotry
BLock
wait
sleep
状态之间如何变化?
wait和sleep方法的不同
新建三个线程如何保障顺序执行
notify()和notifyAll有什么区别
notify随机唤醒一个wait线程
notifyAll 唤醒所有的wait线程
notifyAll 唤醒所有的wait线程
如何停止一个正在运行的线程
线程中的并发安全
synchroniezd的底层原理
synchronized采用互斥的方法让同一时间最多只有一个线程能获取锁,其他线程想获取锁的时候会被阻塞住
Monitor
Montior被叫做监视器:它是JVM实现的 由C++语言编写
Monitor中有三种状态:
1.waitSet:关联调用wait方法的线程,处于waiting状态的线程
2.EntrySet:关联没有抢到锁的线程,处于Blcoked状态的线程
3.Owner:储存当前获取锁的线程,同一时间只能有一个线程可以获取
Montior被叫做监视器:它是JVM实现的 由C++语言编写
Monitor中有三种状态:
1.waitSet:关联调用wait方法的线程,处于waiting状态的线程
2.EntrySet:关联没有抢到锁的线程,处于Blcoked状态的线程
3.Owner:储存当前获取锁的线程,同一时间只能有一个线程可以获取
Synchronized的底层原理——进阶
Monitor属于重量级锁
Monitor属于重量级锁:它涉及到用户态和内核态的切换,和进程上下文的切换
成本较高,性能较低
成本较高,性能较低
锁升级
偏向锁和轻量级锁:主要解决在没有多线程竞争下或者没有竞争下场景,因使用传统锁造成性能开销问题
轻量级锁
偏向锁
Java内存模型
CAS
CAS compare and swap(比较再交换) 它是乐观锁,它主要保证无锁区域的线程操作共享数据的原子性
CAS本质上是乐观锁,不怕别的线程修改变量,改了之后通过自旋的方法重试
CAS本质上是乐观锁,不怕别的线程修改变量,改了之后通过自旋的方法重试
子主题
加载某一个类,先委托上一级的加载器进行加载,如果上级加载器也有上级,则会继续向上委托,如果该类委托上级没有被加载,子加载器尝试加载该类
CAS如何保证原子性?
CAS数据的交换流程:
修改的前提是旧内存和主内存的数据一致
CAS的底层实现
Volatile
禁止指令重排
线程间的可见性
AQS(Abstarct Queue Synchronized 抽象队列同步器 也是锁机制
AQS 和synchronized的区别
ReentractLock的原理
可重入锁
优点:可中断,可以设置超时时间,可以重入
可以设置超时时间
优点:可中断,可以设置超时时间,可以重入
可以设置超时时间
实现原理:
主要利用AQS队列(主要)+CAS来实现的,支持公平锁和非公平锁
主要利用AQS队列(主要)+CAS来实现的,支持公平锁和非公平锁
死锁产生的条件
一个线程同时获取多把锁
一个线程同时获取多把锁
死锁的诊断:使用JDK自带的工具
JPS:输出JVM运行中的进程状态信息
Jstrack:线程堆栈信息
JPS:输出JVM运行中的进程状态信息
Jstrack:线程堆栈信息
jconsole:位于java安装目录 bin目录下
VisualVM:故障处理工具
位于java安装目录bin目录下
位于java安装目录bin目录下
ConcorrentHashMap
1.7版本的concorrenthashmap:用的是分段数组+链表实现
采用了segment的设计,通过hash值来计算位置
JDK1.8之后采用数组+链表/红黑树
1.8放弃了segment数组臃肿的设计,和hashMap的数据结构是一样的:
数组+红黑树+链表
采用CAS自旋+synchronized 来保证并发安全进行实现
数组+红黑树+链表
采用CAS自旋+synchronized 来保证并发安全进行实现
线程池
线程池的核心参数
线程池的执行原理
corePoolSize 核心线程数
MaximumPoolSize 最大线程数:核心线程数+救济线程最大数目
KeepAliveTime生存时间
unit时间单位
workQueue工作队列
threadFactory线程工厂
handler拒绝策略
线程中有哪些阻塞队列:
数组结构的有界阻塞队列
链表结构的有界阻塞队列
数组结构的有界阻塞队列
链表结构的有界阻塞队列
LinkBlockingQueue:单向链表,默认无界支持有界,需要两把锁 锁头尾
ArrayBolckingQueue:强制有界,数组,一把锁
确定核心线程数
I/O密集型:文件读写,DB读写,网络请求
核心线程数大小2N+1
CPU密集型:计算型代码,bitmap转换
核心线程数N+1
线程池的种类有哪些
创建固定线程数的线程池:任务量已知,比较耗时
单例化的线程池,按顺序执行的任务
可缓存的线程池:任务比较密集,任务执行时间较短
提供延迟和周期执行
为什么不建议使用Executors创建线程池
使用场景(重点)
Semaphore使用步骤
ThreadLoacl概述
ThreadLocal内存泄漏问题
强引用
弱引用
软引用
虚引用
JVM
JVM的组成
程序计数器
线程私有的内部保存用于保存字节码的行号,用于记录执行的字节码指令的地址
Java堆
用于保存对象实例,数组,当堆没有内存空间可以分配给实例,抛出outofMemory异常OOM异常
1.7和1.8的区别是什么?
虚拟机栈
每个线程运行时,所需要的内存叫虚拟机栈
每个栈都有多个栈帧组成,每个方法需要的内存
因为是局部变量,每次线程调用方法都会新建一个,每个线程一份所以是线程安全
如果StringBuilder是成员变量所有线程共享
如果StringBuilder是成员变量所有线程共享
帧栈过多导致栈内存溢出,递归调用
方法区
各个线程共享的内存区域
存储类的信息,运行时常量池
虚拟机启动的时候创建,关闭虚拟机时候释放
直接内存
直接内存并不属于不属于JVM的内存结构,不由JVM进行管理。用于数据缓冲区,分配回收成本较高,读写性能高
和常规IO相比减少了Java堆内存和系统内存的互相复制
类加载器
类加载器是什么
JVM只会执行二进制文件,类加载器的作用是将字节码文件加载到JVM中,从而让Java程序启动起来
双亲委派模型!!
JVM的双亲委派机制特点
避免某一个类会被重复加载,父类被加载后无需被加载保证唯一性
保护类的API不会被修改
保护类的API不会被修改
类装载执行过程
类从加载到虚拟机中开始,直到卸载为止,它的整个生命周期包括了︰加载、验证、准备、
解析、初始化、使用和卸
载这7个阶段。其中,验证、准备和解析这三个部分统称为连接(linking)
解析、初始化、使用和卸
载这7个阶段。其中,验证、准备和解析这三个部分统称为连接(linking)
垃圾回收
什么是垃圾回收?
引用计数法
可达性分析
哪些对象可以作为GCRoot?
垃圾回收算法
标记-清除算法
将垃圾分为两个阶段一个是标记-一个是清楚
利用可达性分析算法得到垃圾并标记
之后对这些标记的可回收内容进行垃圾回收
内存碎片问题比较严重
利用可达性分析算法得到垃圾并标记
之后对这些标记的可回收内容进行垃圾回收
内存碎片问题比较严重
复制算法
标记-整理算法:性能有一定影响
分代回收
堆被分为了两份:新生代 :老年代=1:2
JVM的垃圾回收器
串行垃圾回收器:适合堆内存较小,个人电脑
Serial新生代,复制算法
Serial-all老年代,标记-整理算法
并行垃圾回收器:JDK默认的垃圾回收器
Parallel New 新生代,复制算法
Paraller Old 老年代 标记-整理
并发垃圾回收器:垃圾回收时,应用可以适用
并发的,用标记-清除,老年代的垃圾回收
G1垃圾回收器
G1具体
JVM的实践
JVM调优的参数
war包部署在tomcat
jar包部署在启动参数设置
设置堆的空间大小
虚拟机栈的设置
年轻代的Eden区和两个survivor区大小比例 8:1:1
设置垃圾回收器
Java内存泄漏
CPU飙高
企业场景篇
框架中的设计模式
项目中的项目模式!
工厂方法模式
简单工厂模式
工厂方法模式
抽象工厂模式
策略模式
工厂+策略模式:
订单的支付策略
物流运费阶梯计算
打折促销300 9折 2008折
只要代码中有冗长的if else或者switch分支都可以策略模式优化
工厂+策略模式:
订单的支付策略
物流运费阶梯计算
打折促销300 9折 2008折
只要代码中有冗长的if else或者switch分支都可以策略模式优化
责任链模式
避免请求发送者,和多个请求处理者耦合在一起,所有的请求处理者通过前一个对象记住其下一个对象的引用而形成一条链
请求发生之后可以沿着这条链找到有对象处理它为止
请求发生之后可以沿着这条链找到有对象处理它为止
责任链的设计模式
常见的技术场景!!!!
单点登录这块你是怎么做的?
单点登录/SSO是什么?:用户只需要登录一次就可以访问所有信任的应用系统
JWT如何解决单点登录?
解释下单点登录:
1.介绍自己项目中所涉及的单点登录(如果没有可以说实现思路)
2.使用JWT来解决单点登录
I:用户访问其他系统之后,网关会判断token是否有效
II:token无效的情况下会返回401,前端会跳转到登录页面
III:用户发送登录请求之后会返回一个浏览器token,将token存放到cookie中
IV:再访问其他服务器之后,需要携带token,通过网关统一验证后路由到目标服务
1.介绍自己项目中所涉及的单点登录(如果没有可以说实现思路)
2.使用JWT来解决单点登录
I:用户访问其他系统之后,网关会判断token是否有效
II:token无效的情况下会返回401,前端会跳转到登录页面
III:用户发送登录请求之后会返回一个浏览器token,将token存放到cookie中
IV:再访问其他服务器之后,需要携带token,通过网关统一验证后路由到目标服务
权限认证如何实现的?
后台管理系统,后台更注重权限认证,RBAC模型来指导实现权限
Role Base Access Control
后台管理系统,后台更注重权限认证,RBAC模型来指导实现权限
Role Base Access Control
三个基础部分组成:用户,角色,权限
五张表的结构
五张表结构的例子:
后台管理系统开发经验。
介绍RBAC权限模型和五张表的关系(用户,角色,权限)
使用什么样的权限框架?springsecurity
介绍RBAC权限模型和五张表的关系(用户,角色,权限)
使用什么样的权限框架?springsecurity
上传的数据安全性你是如何控制的
网络传输的安全性
网络传输的安全性
对称加密:文件加密和解密使用的是相同的密钥。加密也可以用来解密
非对称加密
使用的是非对称加密,给前端一个公钥加密之后传递到后台解密之后处理数据
文件很大的用对称加密,速度快 但是不能保存敏感信息
文件很小的适合用非对称加密,速度慢,但是安全性高
文件很大的用对称加密,速度快 但是不能保存敏感信息
文件很小的适合用非对称加密,速度慢,但是安全性高
你在项目中遇到过那些棘手的问题
你们是怎么做压测(性能测试)的
你们项目中日志是怎么采集的
为什么要采集日志?
定位系统问题的重要手段,根据日志信息快速定位系统中的问题
定位系统问题的重要手段,根据日志信息快速定位系统中的问题
采集日志的方式有哪些?
常规采集:按天保存到一个日志文件
ELK(比较重要)ElasticSearch,Logstash,Kibana
常规采集:按天保存到一个日志文件
ELK(比较重要)ElasticSearch,Logstash,Kibana
查看日志命令
怎么快速定位瓶颈
生产问题怎么排查?
java基础题
#{}和${}的区别是什么
#{}是预编译,是一个占位符,${}是字符串替换,是拼接符
Mybatis处理的时候,会将sql中的#{}替换为?,调用Preparestatement来赋值,保证sql不会被注入
${}是将你传过来的值之间替换进去,调用statement来赋值容易被注入
Mybatis处理的时候,会将sql中的#{}替换为?,调用Preparestatement来赋值,保证sql不会被注入
${}是将你传过来的值之间替换进去,调用statement来赋值容易被注入
谈谈你对IOC的理解
容器概念
实际上是一个map用来存放各种对象map,在启动的时候会读取配置文件的
bean节点根据全限定类名反射创建对象到map里。
bean节点根据全限定类名反射创建对象到map里。
控制反转
没有引入IOC之前,A对象依赖于对象B,那么在初始化或者运行到某一节点时候,需要去主动
创建B或者使用已经创建的B对象,使用权在自己手里
引入IOC之后,A对象和B对象失去了直接联系,IOC来控制对象B需要注入到对象A的地方
创建B或者使用已经创建的B对象,使用权在自己手里
引入IOC之后,A对象和B对象失去了直接联系,IOC来控制对象B需要注入到对象A的地方
依赖注入
由自身管理变成了IOC容器的主动注入
BeanFactory和ApplicationContext的区别?
ApplicationContext是BeanFactory的子接口
它提供了更完整的功能。
BeanFactory采用的是延迟加载的形式来注入Bean,只有到某一时刻才会进行Bean实例化
ApplicationContext是在容器启动的时候就加载所有的Bean,在启动的时候就可以发现配置错误
ApplicationContext的缺点就是占用内存空间,应用程序配置较多的时候启动比较慢
BeanFactory和applicaitoncontext都支持BeanPostProcesser,BeanFactoryPostProcesser使用
区别在于BeanFactory需要手动注册,ApplicationContext自动注册
它提供了更完整的功能。
BeanFactory采用的是延迟加载的形式来注入Bean,只有到某一时刻才会进行Bean实例化
ApplicationContext是在容器启动的时候就加载所有的Bean,在启动的时候就可以发现配置错误
ApplicationContext的缺点就是占用内存空间,应用程序配置较多的时候启动比较慢
BeanFactory和applicaitoncontext都支持BeanPostProcesser,BeanFactoryPostProcesser使用
区别在于BeanFactory需要手动注册,ApplicationContext自动注册
==和equals的区别
==对比的是栈中的值,equals对比的是两个字符串的内容
final的作用
修饰类
类不可被继承
修饰方法
修饰变量
变量一旦被赋值无法修改
java类加载器有哪些?
BootStrapClassLoader
ExtClassLoader
AppClassLoader
Resource 和Autowired的区别是什么
Autowired是spring里面提供的一个注解,默认是根据类型来实现bean的依赖注入
Autowired里面有一个require属性默认值是true,表示强制要求bean实例的注入
如果启动的时候IOC容器里面不存在对应类型的bean启动的时候就会报错。
Autowired是根据类型来实现注入的,如果一个ioc容器里面存在多个相同的bean就会报错
可以使用primary的注解来解决,这个表示主要bean存在多个类型的时候优先使用primary的注解
qualifer类似于条件bean根据bean的名字找到需要的目标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匹配
如果使用name,spring会根据名字进行依赖注入,如果使用type,spring会根据类型实现依赖注入。如果都没有配置默认情况下会根据类型进行依赖注入,默认是name匹配
springboot如何解决跨域问题
由于浏览器有同源策略的一个限制,只能访问同源的资源不能访问其他源的资源
目的就是不破坏同源策略的限制下能够安全的进行数据的共享和交互
使用WebMvcConfigurer接口重新appCorsMapping方法来配置允许跨域的请求源
目的就是不破坏同源策略的限制下能够安全的进行数据的共享和交互
使用WebMvcConfigurer接口重新appCorsMapping方法来配置允许跨域的请求源
幂等性是什么怎么处理
在计算机领域里幂等性指的是方法被重复使用之后造成的影响和第一次相同,一般常见于用户的重复请求和恶意攻击导致请求多次重复执行
在分布式架构中,为了避免网络导致的数据丢失通常会使用超时重复机制,但是容易导致服务端口被重复调用
使用Redis里面的setnx指令,比如MQ消费的场景,避免MQ重复消费导致数据被多次修改,接收到MQ消息的同时,
消息就会通过setnx写入Redis里面一旦消息被消费过就不会重复消费
在分布式架构中,为了避免网络导致的数据丢失通常会使用超时重复机制,但是容易导致服务端口被重复调用
使用Redis里面的setnx指令,比如MQ消费的场景,避免MQ重复消费导致数据被多次修改,接收到MQ消息的同时,
消息就会通过setnx写入Redis里面一旦消息被消费过就不会重复消费
ConcorrentHashMap中的key为什么不允许为null
避免多线程的环境下出现歧义的问题,如果我们通过get(key)来获取value的时候返回的结果为null
无法判断put(k,v)中key本身不存在或者是value为null值
无法判断put(k,v)中key本身不存在或者是value为null值
MyISAM和Innodb区别
MyISAM和Innodb区别都是mysql里面的两个存储引擎
在mysql5.5之前用的是MyISAM在5.5后默认是innodb我们平时开发也用的是innodb
在mysql5.5之前用的是MyISAM在5.5后默认是innodb我们平时开发也用的是innodb
MyISAM和innodb数据存储的方式不同,一个是索引和数据分开,innodb存储在同一个里面
innodb支持ACID特性的事务处理,MyISam只支持表锁,innodb支持表锁行锁等很多锁
innodb支持外键,MyIsam不支持外键,如果大部分表需要查询操作可以用MyIsam
innodb支持ACID特性的事务处理,MyISam只支持表锁,innodb支持表锁行锁等很多锁
innodb支持外键,MyIsam不支持外键,如果大部分表需要查询操作可以用MyIsam
TCP协议是什么,为什么要设置三次挥手
TCP是可靠的基于字节流的面向连接的传输层的协议。
在收发数据之前必须进行可靠的数据连接,建立连接三次握手(通信双方要发送三次请求),断开连接的四次挥手
在收发数据之前必须进行可靠的数据连接,建立连接三次握手(通信双方要发送三次请求),断开连接的四次挥手
cookie和session区别
Cookie存储在客户端,session存储在服务器端。cookie是通过客户端的浏览器中存储数据来实现的,session在服务器端来创建会话对象来存储数据
由于cookie存储在客户端所以不太安全,而且cookie的存储数据容量比session少。
Session通常不支持跨域访问,但是由于session存储在服务器端,只要在客户端保存会话ID,减少网络传输的数据量
由于cookie存储在客户端所以不太安全,而且cookie的存储数据容量比session少。
Session通常不支持跨域访问,但是由于session存储在服务器端,只要在客户端保存会话ID,减少网络传输的数据量
分库分表如何实现?
确定分片的策略可以根据业务的需求和数据特点来确定分片规则,按照用户id,时间地点
分布式锁的实现方式有哪些?
基于数据库的实现
可以通过设置唯一的标识来实现分布式锁
基于缓存的实现
使用redission来实现分布式锁,setnx命令锁的获取
基于分布式算法的实现
raft协议来实现分布式锁,选举制度来保证一致性
CPU飙升如何排查
使用java里bin包下的visualVm来诊断
使用gdb工具获取进程调用栈信息,查询是否有死循环或者递归的问题
线上应用出现了bug怎么办
首先就是启用备用的服务器,降低负载,限流的方式来稳定应用
可以通过查看日志监控系统等信息来定位问题
如果是实在恶性的bug 进行回滚操作
spirng事务和mysql事务是否一样?
spring事务是通过声明式事务管理和编程式事务管理来实现的
通过在方法上添加@Transcational注解来实现对事务的控制,提供灵活的事务传播行为
通过在方法上添加@Transcational注解来实现对事务的控制,提供灵活的事务传播行为
msql是根据start transcation,commit,rollback等sql语句来控制事务的开启提交和回滚,保证了并发状态下的一致性
事务悬挂和空回滚
主要出现在多层嵌套的事务中,并且使用了不同的事务传播行为
事务悬挂指的是内层事务开始时候,会挂起外层事务,如果内存事务没有正常完成或者回滚那就处于一直等待状态
空回滚,内层事务回滚外层事务,即使外层事务没有出现异常
事务悬挂指的是内层事务开始时候,会挂起外层事务,如果内存事务没有正常完成或者回滚那就处于一直等待状态
空回滚,内层事务回滚外层事务,即使外层事务没有出现异常
springboot和ssm的区别?
springboot通过约定大于配置的思想减少了繁琐的XML配置,SSM需要手动配置
springboot开发效率更高,便于部署和运行,依赖管理更简单
springboot开发效率更高,便于部署和运行,依赖管理更简单
StringBuffer和Stringbuilde的区别?
StringBuffer是线程安全的使用了synchronized关键字进行同步,但是它性能比较低。如果在多线程的环境下进行操作用stringbuffer
Stringbuilder因为没有同步处理所以性能比较高,相对的线程不是安全的,如果在单线程的环境下运行就用stringbuilder
工作中怎么处理异常?
使用trycatch来异常捕获处理,或者是用throws关键字来抛出异常,使用finally块。或者是自定义异常类
volatile和synchronized 的区别?
volatile可以保证指令重排和可见性。指令重排使用的是读写屏障防止越过,可见性是操作共享变量的同时对其他线程可见
synchronized可以保证原子性,通过互斥锁的方法来实现原子性和线程安全。volatile性能比较好
synchronized可以保证原子性,通过互斥锁的方法来实现原子性和线程安全。volatile性能比较好
mybatis的二级缓存
二级缓存适合相对稳定的数据,有可能造成数据不一致的问题。默认使用的是perpetualCache作为缓存实现
用来减少重复查询的开销
用来减少重复查询的开销
mqtt是轻量级发布的订阅协议,用于低带宽,高延迟,不可靠的网络环境进行消息传输
它支持三种不同消息的传递数量等级
QoS0:最多一次,消费者发布消息后不会收到确认,可能会造成丢失
QoS1:最少一次,消息发布者会收到消息确认,确保消息最少被重复传输一次,容易造成数据重复问题
QoS2:只有一次,消息分布着会收到消息确认,确保消息只被传输一次,可能会有更高的延迟和开销
它支持三种不同消息的传递数量等级
QoS0:最多一次,消费者发布消息后不会收到确认,可能会造成丢失
QoS1:最少一次,消息发布者会收到消息确认,确保消息最少被重复传输一次,容易造成数据重复问题
QoS2:只有一次,消息分布着会收到消息确认,确保消息只被传输一次,可能会有更高的延迟和开销
广泛应用于物联网中:轻量级,节约带宽,和灵活。基于TCP/IP的协议栈来传输
单点登录和实现流程?
单点登录这个目的就是用户只要登录一次就可以在多个系统和应用之间无缝访问
如何防止超卖问题?
第一点就是使用同步锁或者分布式锁来确保原子性,
第二点就是高并发的情况下可以把库存数据预热到Redis缓存中
第三点就是如果某个商品访问量较大,可以对库存进行拆分,降低访问的压力之后对单个sku的数据加锁
第二点就是高并发的情况下可以把库存数据预热到Redis缓存中
第三点就是如果某个商品访问量较大,可以对库存进行拆分,降低访问的压力之后对单个sku的数据加锁
java对象的创建过程
实例化对象的时候,JVM首先会检查目标对象是否已经被加载或实例化,
如果没有jvm会加载目标类并且完成初始化。类加载是通过类加载器来实现的主要是把一个类加载到内存中
之后对静态变量,成员变量,静态代码块进行初始化,目标类被初始化以后就可以去常量池找类元信息。
目标对象的大小在类加载完成之后就已经确定了,需要为新创建的对象根据目标对象的大小在堆内存里面去创建空间。
内存分配的方式有两种,第一种是指针碰撞,第二种是空闲列表,jvm会根据内次是否规整来决定分配方法,之后把普通
成员变量初始化为0值保证对象里面的实例字段不用初始化就可以直接使用,之后jvm会对目标对象的对象头进行设置
类员信息,GC分代年龄,hashcod等。接下来就是执行目标对象的init方法,初始化成员变量的值,执行构造块,最后调用
目标对象的构造方法
如果没有jvm会加载目标类并且完成初始化。类加载是通过类加载器来实现的主要是把一个类加载到内存中
之后对静态变量,成员变量,静态代码块进行初始化,目标类被初始化以后就可以去常量池找类元信息。
目标对象的大小在类加载完成之后就已经确定了,需要为新创建的对象根据目标对象的大小在堆内存里面去创建空间。
内存分配的方式有两种,第一种是指针碰撞,第二种是空闲列表,jvm会根据内次是否规整来决定分配方法,之后把普通
成员变量初始化为0值保证对象里面的实例字段不用初始化就可以直接使用,之后jvm会对目标对象的对象头进行设置
类员信息,GC分代年龄,hashcod等。接下来就是执行目标对象的init方法,初始化成员变量的值,执行构造块,最后调用
目标对象的构造方法
实战项目篇
农业电商服务平台
说一下你们的服务电商平台的整个项目流程
1.我们首先进行了需求分析和规划(包括项目有关的所有受益者,农民,消费者,物流服务商等)
2.确定了必要的功能列表(产品展示,订单管理,支付,物流追踪,用户管理等内容)
2.确定了必要的功能列表(产品展示,订单管理,支付,物流追踪,用户管理等内容)
1.后端使用java,springboot,springmvc还有mysql来编写业务逻辑,API接口和数据持久化的逻辑
2.创建了所需要的表,视图等
3.集成第三方服务,支付网关,短信服务,物流api
4.我们还进行了单元测试,集成测试和系统测试保证正常工作
2.创建了所需要的表,视图等
3.集成第三方服务,支付网关,短信服务,物流api
4.我们还进行了单元测试,集成测试和系统测试保证正常工作
之后是部署和上线,部署后端到阿里云,进行负载测试
你们的服务平台一般有多少数据量?
我们是小型的服务平台 有1台服务器
你们那个平台的线上运行情况如何?
我们的网站有五万的用户,平均日活为0.4.也就是日活为2万。集中时间段为4个小时,平均点击量为三,qps为4.
你们项目中分布式锁用在了什么地方
我们一般用在了订单管理,多个用户购买同一商品的时候保证一致性防止超卖,第二个地方就在库存管理,避免数据不一致的问题。
第三点用的是农产品价格更新的时候,不被干扰防止显示错误价格。
第三点用的是农产品价格更新的时候,不被干扰防止显示错误价格。
你负责的项目中redis用在了什么方面?
缓存管理:将常用的数据存储在缓存中,将频繁访问公共资源的数据(图片,文件,配置信息)
会话管理:用户的登录状态,权限信息等
计数器:对资源的访问次数,下载次数进行统计,方便计数管理
发布/订阅:实现消息发布和订阅功能,实现消息的发布和订阅机制
你的项目是怎么做的测试
用的swagger做的本地测试,
用JenKins做单元测试
问项目是否上线
我走的时候项目是交付了,但是具体的部署服务器是由甲方的运维部署的,我不知道;
因为我做的是乡村治理综合平台的公共管理模块相关的内容,我们用的是敏捷开发模式,约定是六个月上线。用了半个月的时间建表和分析需求,后面每个月会做版本会做
迭代开发,第四个月交付给客户,有意见及时修改
迭代开发,第四个月交付给客户,有意见及时修改
我们项目组有测试环境用的是公司租了一台Linux服务器,每个迭代周期将开发好的功能打包上传(maven包打包成jar包)到测试环境及时解决,用swagger进行本地测试,用Jenkins进行单元测试,用git来管理代码
使用swagger用于测试Restful,生成可读性的API文档,提供给其他开发人员或测试团队进行测试。
使用swagger用于测试Restful,生成可读性的API文档,提供给其他开发人员或测试团队进行测试。
项目开发好之后,我们项目经理和运维一起把项目部署到对方指定的服务器上,对方用的是云服务器进行部署的,具体的细节我不太清楚。
你的项目中用了什么系统开发的
用的windows写的,使用的Linux服务器部署的
你在你负责的模块项目开发中遇到的难题
故障报修中通知机制:为了保证实时性使用RabbitMq来实时通知和更新工单状态,用到了Reddision分布式锁来保证多个操作的正确性
和一致性
和一致性
监控告警这个子模块中,我当时碰到了多次触发相同告警情况,设置了冷却时间,还有告警的阈值,我们也有一个相关的告警表:
设备ID,类型,触发时间等内容,如果相同的告警就被判定重复告警
设备ID,类型,触发时间等内容,如果相同的告警就被判定重复告警
用户参与反馈遇到了一些用户账户的安全性问题,用了springsecurity认证框架来实现用户登录。
你在项目开发中遇到的棘手的问题?
刚开始我不熟悉数据库性能调优的问题,但后来熟悉了。
我们项目在部署后,会对MySQL数据库进行监控,一旦超过5s我们就会收到告警通知,
遇到长SQL以后,我们会用执行计划(Execute Plan)分析该sql,
len和key_len看是否命中索引,extra判断是否有回表,type看是否有优化空间
遇到长SQL以后,我们会用执行计划(Execute Plan)分析该sql,
len和key_len看是否命中索引,extra判断是否有回表,type看是否有优化空间
最常见的原因就是索引,没使用联合索引
使用了MyCat分库分表 根据业务去拆分表
刚开始我只知道在windows里开发,不熟悉linux操作,尤其是在linux里看日志的操作
用vi命令打开日志文件,再用根据错误关键字和时间,搜索找到上下文,
再根据该日志的线程ID去看在该日志文件的其它 日志
再根据该日志的线程ID去看在该日志文件的其它 日志
请求类型应该是post但是我发的是get,最后加了异常处理机制
问监控怎么做:这套监控是运维或项目经理搭建的
对接第三方接口要考虑什么?
正常情况下是按照第三方的接口文档去写的
有些的会提供工具包
正常情况下是按照第三方的接口文档去写的
有些的会提供工具包
首先就是安全性问题,需要涉及到数据的跨网络传输,为了数据被拦截和篡改,使用https通信协议和数据签名
接口的稳定性和可靠性
影响用户体验,和业务的正常流程
接口是否存在访问限制或费用
并发量限制,评估是否满足当前业务需求
存在费用限制,也要评估费用问题
flowable和actitivi
它俩都是开源的业务流程管理平台,帮助自动化和优化业务流程
如何使用?
什么是工作流?
业务之间的各个步骤以及规则进行抽象和概括性的描述,
以特定的语言为流程建模,并让计算机进行计算和推动。
业务建模用的是BPM2.0的国际通用语言
缺点就是:如果流程做变更就需要做大量的更改
以特定的语言为流程建模,并让计算机进行计算和推动。
业务建模用的是BPM2.0的国际通用语言
缺点就是:如果流程做变更就需要做大量的更改
Flowable流程引擎
(将业务中的复杂的业务流程抽取出来)
(将业务中的复杂的业务流程抽取出来)
使用专门的建模语言BPMN2.0进行定义,流程由flowable进行监管
一,首先用BPMN来定义流程
二,使用flowable框架来实现流程
二,使用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应用程序,提供了更现代化和可定制的用户界面。
项目背景: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应用程序,提供了更现代化和可定制的用户界面。
哈尔滨移动面试题
mysql的优化
索引优化
数据量大,表查询频繁的时候需要用索引
索引的数量不宜过多
尽量使用联合索引
常作为查询,排序分组字段
SQL语句的优化:通过explain进行分析查询
避免使用select *
尽量多使用Inner Join
使用聚合查询的时候尽量使用union all 而不用union
表设计结构的优化:根据业务需求可以进行 垂直分库分表或者是水平分库分表
线程的使用
创建线程对象,
启动线程
线程执行
详细说说map集合的存储方式
HashMap
用哈希表来存储键值对
TreeMap:
通过红黑树来存储键值对。
LinkHashMap;
维护了双向链表,,除哈希表来存储键值对之外还有指向前后的两个指针
常用的集合有哪几种?
Collection 单列集合
List集合:有序可重复的
Arraylist:适合查询,不适合添加或者删除元素
LinkLis:链表适合添加删除元素,不适合查询t
Set集合:无序不重复的
HashSet:基于hash表实现的,无序的。查找添加删除等操作效率高 O(1)
不允许重复操作,线程不安全
不允许重复操作,线程不安全
TreeSet:基于红黑树来实现的,有序,不允许重复操作,线程不安全 效率略低hashset
Map是双列集合
HashMap:线程不安全的,他在单线程的环境下性能较好,适合在只有一个线程写入多个线程读取的情况下
ConcurrentHashMap 线程安全的,采用了分段锁的机制并发比较好
TreeMap红黑树
实现线程的方法
继承Tread类:重写run方法
实现Runnable接口:提高代码的可读性和可维护性
实现Callable接口:可以返回结果和抛出异常
int和Interger的区别:
1,int的初始值为0,interger的初始值为null
2,int是java基本的数据类型,integer是包装类,可以作为泛用类型也可以做方法对象
2,int是java基本的数据类型,integer是包装类,可以作为泛用类型也可以做方法对象
jquery和JavaScript之间的联系和区别
jquery和javascript取值
Jquery的取值是通过$().val()的形式,需要添加额外的库
javaScript的取值是通过document.的形式来取值的,他不需要额外的库更加原生
说一说你的项目:从担任的角色,负责的东西,难点处理三个方面来说
担任的角色,就职期间担任了后端开发的模块,被分配到了公共资源 管理相关功能的组。
负责的东西,我负责了故障报修和工单管理模块,用户参与和反馈模块,监控设备告警功能的实现相关的业务。
用户首先发现故障或者需要维修的信息之后,通过平台提交报修请求《
包括相关信息,故障描述,报修人的联系方式,报修地点等
包括相关信息,故障描述,报修人的联系方式,报修地点等
报修请求被接收后,系统会自动生成工单,工单内容包括报修问题的详细描述
报修人信息,报修时间等
报修人信息,报修时间等
将工单会传到维修人员相关的界面上,维修人员会接到工单并进行处理
维修人员处理完毕之后会更新工单状态,记录相关的处理信息。
解决之后工单被标记已解决,工单关闭
相关的表
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,最后加异常处理机制
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的百万数据如何快速查找
0 条评论
下一页