2022Java面试必问基础总结
2022-04-27 22:39:51 1 举报
AI智能生成
登录查看完整内容
2022Java面试必问基础总结
作者其他创作
大纲/内容
主流程后异步发送短信之类的
异步
解耦
流量削峰
什么场景?
MQ
场景
随机缓存时间
热点数据永远不过期
缓存主动更新
缓存高可用部署,集群+主备
大量key同时间过期或者redis宕机,导致大量请求打入db,导致宕机
雪崩
正常id校验
查不到设置null值
布隆过滤器
大量缓存不存在的key请求,直接打到DB
穿透
加锁
热点数据永不过期
定时更新缓存
单个key的大流量请求导致的缓存失效击穿DB
击穿
缓存问题
目的是严格的控制读写缓存的一致性,可以兼顾大部分流量的读性能,也可以控制写入的一致性
也就是说当进行读操作的时候加读锁,不影响其它的读操作,当发生写操作时加写锁,此时读操作暂时阻塞,直接缓存失效并更新数据库后解锁,那么后续的读操作一定是最新值会更新到缓存。
结论:终极解决方案:读写锁控制,必须是分布式的读写锁,比如用redis实现,Redission有封装好的功能
db和缓存的不一致问题怎么解决?
简单来讲就是依次从不同的redis节点获取锁,设置锁的过期时间和获取锁的超时时间,过期时间远大于超时时间,当获取锁的redis节点服务宕机,则会快速的超过超时时间获取锁失败,则会立刻尝试获取下一个redis实例的锁,当大部分redis节点都获取到锁,过期时间大于获取锁的总时间则算获取到锁。这样做就是为了避免单个redis服务节点宕机节点切换导致的获取锁失效问题。
红锁简单解释
red lock
单线程接收,io多路复用放入队列,利用文件分派器分派到不同的命令处理器,扩大了可处理数据的容量,同时保留了原子性
原子性
redis
互斥性
锁超时
可重入性
非阻塞
公平非公平
谁加锁谁释放
特点
使用的redis的hash数据类型,用lua脚本进行的加锁六层
先判断key是否存在,不存在加锁,设置field为客户端id(uuid+thread id),值为1表示加锁次数,设置超时时间30秒
用watch dog监听超时时间,业务没执行完前会每隔十秒进行续期,重置30s
它是可重入的锁,每次加锁value+1
解锁则是每次value-1,直到为0做del操作
redisson
分布式锁
字段尽量Not null
字段类型长度设计合理
尽量遵循数据库三范式,业务逻辑不耦合
建表时
like 前置%不可取
尽量不用or not <>
可以覆盖索引尽量用覆盖索引的写法
join不可过多的表,性能会急剧下降,用小表驱动大表
写SQL
开启慢SQL日志,定期拉取慢SQL进行优化
explain分析SQL,构建合理的索引
上线后
如何优化
聊下mysql的事务隔离级别
readView在RC隔离级别下,每次执行快照都会生成新的读快照
readView在RR隔离级别下,只有在当前事务进行第一次快照读的时候,生成readView,之后快照度都用的当前readView
m_ids:当前活跃事务ID集合
最小活跃事务id,小于它说明事务已经提交
min_trx_id
预分配的事务id,等于当前最大事务id+1
max_trx_id
readView创建者的事务编号
createor_trx_id
readView的数据结构
重点掌握undo log和readView
MVCC
Mysql
如何进行微服务划分?
微服务
作用:是java中的一个关键词,起到互斥锁的作用
锁是对象实例
实例方法
锁是当前类的实例
静态方法
锁是传入对象实例
代码块
修饰对象
用ACC_SYNCHRONIZED来标识
修饰方法
monitorenter和monitorexit指令
修饰代码块
对象实例三部分组成:对象头,对象实际数据、对齐填充,其中对象头的mark word储存着锁信息
实现原理
锁从无锁到重量级锁的升级过程
mark word记录了锁的状态 无锁、偏向锁、轻量级锁、重量级索
jdk1.6之后对synchronized做了很多优化
聊下synchronized
可见性
有序性
volatile
一条线程代码顺序执行,前面的代码在后续代码前执行
程序顺序性规则
锁的加锁对解锁可见
监视器规则
volatile的写操作必定对后续的读操作可见
volatile规则
A对B可见,B对C可见,则A对C可见
传递性规则
线程的start操作对线程执行内容可见
线程启动规则
线程终止规则
interrupt()方法的调用,happen-before与被中断线程的代码检测,也就是对Thread.interrupted()可见
线程中断规则
对象初始化对对象的finalize()可见
对象终结规则
happen-before规则有哪些?
JUC包下实现并发共享和互斥锁的底层机制,实现了比如CountDownLatch、Semaphore、ReetrantantLock等工具
它主要用来进行锁变量的维护,线程的等待和唤醒,锁公平非公平机制的实现
内部使用cas维护state变量进行加锁,用一个FIFO的双向队列进行等待加锁线程的管理
如果有必要,可以讲讲他公平非公平的实现机制:公平锁,当释放锁的时候,队列有等待线程则唤醒下一个节点的等待线程获取锁;非公平则是不管是否有等待线程,都会和新进来的线程进行获取锁的竞争
AQS
并发
可以把依赖的第三方jar包的实例,自动注册到Spring的IOC容器中,不需要再自己手动配置
作用
在启动类上放上@SpringBootApplication注解,里面包含了@EnableAutoConfiguration注解,会负责启动配置类
用法
配置类必须包含@Configuration,里面用@Bean进行实例对象的声明
配置类是在第三方jar包的,它通过Spring的SpringFactoriesLoader加载Spring.factories,而配置类的全包路径就放在这个配置中
Spring拿到配置后通过ImportSelector接口对配置类进行动态加载
核心技术
SpringBoot的自动装配机制了解?
一个轻量级的框架,主要实现的功能为IOC和AOP
为web应用程序提供了MVC的机制
利用AOP的机制实现了很好的事务控制
具有完整活跃的生态,出问题也容易解决
对Spring的理解
IOC控制反转,原来由使用用控制对象的创建,改由Spring容器进行管理
DI依赖注入,将对象的属性通过注解@Autowired或@Resource进行属性注入
三级缓存
对SpringIOC的理解?
总体描述,bean对象从产生到销毁的环节都由容器进行控制,其中包括实例化和初始化两个主要步骤,当然中间会有一些扩展点的存在
实例化对象,通过反射的方式,调用createBeanInstance方法生成对象
当bean对象创建完成,对象属性都是默认值,开始对bean填充属性,调用populateBean
向Bean对象中设置容器属性,会调用invokeAwareMethods方法将容器对象设置到具体的Bean对象中
调用BeanPostProcessor中的前置处理方法来进行Bean对象的扩展工作
调用invokeInitMethods方法来完成初始化方法的调用,如果实现了InitializingBean,调用afterPropertiesSet最后设置bean对象
调用BeanPostProcessor的后置处理方法,完成Bean对象后置处理工作,aop就是在此处实现的,实现接口名字叫AbstractAutoProxyCreator
获取完整对象,通过getBean的方式进行对象的获取和使用
当对象使用完成之后,容器关闭时,会销毁对象,判断是否实现DisposableBean接口,然后调用destroyMethod方法
描述具体步骤:
Spring的bean生命周期?
BeanFactory和FactoryBean都可以创建对象,只不过创建的流程和方式不同,
当使用BeanFactory的时候,必须严格遵守bean的生命周期,经过一系列繁杂的步骤之后才可以创建出单例对象,是流水线式的创建过程
而FactoryBean是用户可以自定义bean对象的创建流程,不需要按照bean生命周期来创建,此接口包含三个方法,isSingleton:判断是否单例对象;getObjectType:获取对象的类型;getObject:在此方法中可以自己创建对象,使用new的方式或者代理的方式都可以,用户按照自己的需要随意去创建对象,在很多框架继承的时候都会实现FactoryBean接口,比如Feign
BeanFactory和FactoryBean的区别?
单例模式,spring中bean大都单例的
工厂模式:BeanFactory
模板方法:postProcessorBeanFactory
观察者模式:listener,event,multicast
Adapter
适配器
BeanWrapper
装饰者模式
aop有责任链模式
责任链
aop动态
代理模式
delegate
委托者模式
builder
建造者模式
不同的加载方式,比如XmlBeanDefinitionReader,PropertiesBeanDefinitionReader
策略模式
Spring用到哪些设计模式?
解释什么是循环依赖?A依赖B,B依赖A
spring中bean对象的创建都要经历实例化和初始化也就是属性填充的过程
通过将对象的状态分开,存在半成品和成品对象的方式,来分别进行初始化和实例化,对应一级缓存中放成品对象,二级缓存放半成品对象
三级缓存value类型是ObjectFactory,是一个函数式接口,不是直接进行调用的,只有在调用getObject方法的时候才会去调用里面的lambda表达式,保证同名的bean对象只能有一个
对三级缓存的理解?
Spring
核心就是管理对JVM中垃圾对象的收集和销毁
GC的理解?
java堆
局部变量表
操作数栈
方法返回地址
动态链接
java虚拟机栈
方法区
程序计数器
本地方法栈
组成
JVM
基于CPU的三层缓存机制,在并发请求的时候会导致缓存不一致性
背景
总线锁是对CPU前端加锁,一旦获取到锁,其它CPU就要等待该CPU释放锁才能继续执行,效率比较低
缓存锁则是针对缓存行进行加锁,颗粒度更细,但带来一定的复杂度,最著名的缓存一致性协议就是mesi
通过总线锁或者缓存锁
怎么解决
具体为当cpu更新数据的时候,会把更新数据先放入store buffer,在去异步通知其它cpu,其它cpu接到消息后也不是马上处理,而是放入invalid queue(失效队列),之后一个个执行缓存失效,目的当然后失效后重新从主内存加载最新的值。但这里会有一个问题,在异步化后如何保证主内存拿过来的数据是最新的,这就是mesi协议来保证了,当修改cpu共享变量后,cpu状态会变为“修改”状态,这时候若发生cpu写共享变量操作,这里会触发一个写屏障,会立即把store buffer的数据全部写入主内容,保证后续操作是正确且最新的。cpu通知其它cpu后其它cpu会变成“失效”状态,这时候这些cpu发生读操作,会触发读屏障,那么会立即把invalid queue的数据全部执行完毕,也就是全部立即失效,保证之后是从主内存读到的最新数据。这样就保证的缓存的一致性
加入了store buffer和invalid queue通过异步通知机制,进行更进一步优化
怎么提升效率
java内存管理
JMM
SqlSessionFactoryBuilder加载mybatis-config.xml配置,创建对应的SqlSessionFactory
SqlSessionFactory通过openSession获取sqlSession,SqlSession的创建会传入Exceutor交由它去执行
sqlSession通过getMapper获取MapperStatement,通过Executor创建的StatementHandler进行SQL的执行和入参,结果的处理
mybatis
ArrayBlockingQueue采用数组有界列表,LinkedBlockingQueue是可以指定大小的双向链表的结构
ArrayBlockingQueue存取队列用的同一把ReentrantLock锁,LinkedBlockingQueue用putLock负责写入,takeLock负责读取,并发效率上会更高
两者的插入删除的开销不一样,ArrayBlockingQueue存取不会额外产生销毁对象实例,而LinkedBlockingQueue会创建额外的Node对象,更占用内存给gc带来压力
LinkedBlockingQueue和ArrayBlockingQueue的区别?
1.mysql的myisam不支持事务
自身调用自己方法
没加@Transactional注解
2.没有被Spring管理
3.没有加事务管理器
4.异常吃掉没有抛出来
5.异常没有定义回滚,默认是RuntimeException
6.设置的事务传播类型是not_support
Spring事务失效的情况
发生冲突,往后找可以放的空间
开放定址发
发生冲突再hash
再hash法
类似hashMao,发生冲突加入链表
链地址法
发生冲突加入溢出区的空间
建立公共溢出区
hash冲突的解决方案?
通过TLS/SSL加密
加密方式
https
大致可以概括为:容器化+微服务+devOps+持续交付+声明式API+服务网格
什么是云原生?
基础
你做的项目遇到过什么难点,怎么解决的?
项目必问
2022Java面试必问基础总结
0 条评论
回复 删除
下一页