java面试题
2024-08-26 15:25:04 0 举报
AI智能生成
这是一道Java面试题,考查了求职者对Java编程核心概念的掌握程度。本面试题涉及到Java多线程编程,具体涉及到线程的优先级和线程同步机制。在解答时,求职者需要解释清楚线程的优先级概念,并说明如何在Java中实现线程同步,如使用synchronized关键字或者Lock对象。此外,求职者还需要解释为什么需要线程同步,以及线程同步可能带来的问题,如死锁。
作者其他创作
大纲/内容
sql-连接器-
执行流程
InnoDB
各引擎的区别
架构
B+树
索引底层数据结构
主键索引 查啦一遍非聚簇索引没查到又查啦一遍聚簇索引
聚簇索引 非聚簇索引 回表
查询的字段通过索引都能查到 eg:在A字段建索引 查询A+id字段 不用回表
覆盖索引
最左匹配 %like 运算 数值单引号 where or
索引失效
索引
原子 一致 隔离 持久
ACID
脏读 不可重复读 幻读
问题
读未提交 读已提交 可重复读 串行化
隔离级别
并发事务
事务A修改数据未提交 存活事务id列表有 事务B的id大于事务A 事务A的修改对事务B不可见
eg:解决脏读
1.事务id是自增的 2.存活事务id列表可以查到那些事务没提交 3.数据某个时间节点的快照
依据
MVCC解决并发事务
事务
行锁 表锁
锁
binlog
Mysql server层 主从同步 数据恢复
重做日志 刷脏
redolog
回滚日志 链表 链接啦修改前的数据版本 MVCC有用到
uodolog
Innodb保证acid
日志
给binlog到从
异步
给binlog到从 从确认可执行成功后 再提交
半同步
主从同步
分库分表
开启慢查询日志
定位慢Sql
explain分析执行计划
分析执行计划
考虑覆盖索引,避免索引失效
优化索引
优化Sql
Sql优化
高可用
如何解决主从同步的数据不一致性
select name sum(socre) form table gro
一个成绩表 查询总分最高的3个学生
Mysql
String Hash Set Zset bitmap list
数据类型
布隆过滤器bitmap实现
查询不存在key
穿透
互斥锁/逻辑过期
Key过期+大量并发
击穿
哨兵模式/设置不同的过期时间/多级缓存
redis掉线/大量Key同时过期
雪崩
缓存三兄弟
先删库再删redis过一段时间后再删redis
延迟双删
通过binlog日志将数据变化发给消息中间件 redis消费消息实现延时一致性
binlog日志订阅
持久化
有数据丢失风险
bgsave开启子线程做
快照
RDB
追加文件越来越大
与磁盘交互 指令信息异步刷盘
指令追加
AOF
双写一致性
用的时候检查
惰性删除
定期删除
过期删除
不写入新数据
比较过期时间淘汰
最少使用算法淘汰
淘汰策略
过期删除和淘汰策略
全量同步
增量同步
哨兵模式
多个master节点存不同数据
海量存储
多个master节点 多个slave节点
高并发写 读
引入hash槽 不同master节点有不同hash槽范围 根据key计算hash值 取模后 根据值找节点 访问任意节点自动路由
具体是如何读写
分片集群
读写分离
redis如何保证主从一致性
Redis
运行时能获取任意一个类的信息eg:给类名拿到类信息
线程 进程
new Thread 实现runable callable接口 线程池创建
创建方式
新建 可运行 阻塞 等待 时间等待
新建 没到资源->阻塞 代码里加啦wait就进入等待状态 notity可以唤醒 sleep加时间->时间等待
抢到资源->可运行 start 运行线程
状态 变化
join
线程顺序执行
wait是Object的方法 Sleep是Thread的方法 可以在主线程使用
wait sleep
线程
jvm中通过进入和推出monitor监控器实现的
synchronize底层原理
synchronize是关键字 lock是接口 有实现类Reentranlock 与sunchronize都是可重入锁
Reentranlock 与sunchronize都是可重入锁 加锁次数与释放次数要一致
synchronize lock
基于AQS实现的 子类有公平锁和非公平锁 renntranlock默认构造函数是非公平锁 一旦调用lock方法会立即CAS枪锁 不管阻塞队列有无线程等待
Reentrantlock
jdk1.7 segment数据 hashEntry数组 链表
jdk1.8 Node数据 链表红黑树 对数组的每个节点用cas 或者 synoize关键字加锁
底层数据结构
CAS 谁先抢到谁修改
只在链表或树的根节点 加Synchonic锁
加锁的方式
ConcurrntHashMap
java内存模型 把内存分为两块 主内存 工作内存 工作内存存变量副本 每个线程独有 通过主内存交换数据
继承被代理类 重写啦代理类的方法
Cglib
JMM
乐观锁 自旋锁 比较后替换 eg:线程A从主内存拿到变量值修改 拿旧版本与主内存数据比较 一致后替换。CAS失败会一直自旋,直到成功
CAS
悲观锁
AQS
线程安全/锁
核心线程数
最大线程数据
时间单位
生存时间
阻塞队列
核心参数
超过核心线程数 放入阻塞队列 阻塞队列满啦 创建救急线程 超过最大线程数 拒接策略(丢掉线程任务 去掉队列前的线程)
工作流程
看是IO 密集 还是cpu密集 cpu密集要减少上下文切换 N+1 否则2N+1
核心线程数怎么确定
固定线程数
单线程
没有核心线程数 最大线程数是integer.MAX_value
延迟执行
直接用原生的 以上的阻塞队列大小integer的最大值
线程池的种类
线程池
获取数据总页数 设置CountDownLatch 创建线程分页查询数据并导入Hive库提交任务到线程池 计数减1 主线程CountDownLatch.await方法等待计数归零
线程池批量抽取数据到Hive
CompetwFuture thenApply获取线程的执行结果
多线程并发编排
场景
1数据资源线程内共享 2线程间隔离 3.每个线程都有ThreadLoadMap成员变量 key值是ThreadLoad
ThreadLocal
共享内存
线程间共享数据
超卖问题 synconized
原子性
线程停止问题 volitle 让一个线程的修改的变量对另一个线程可见
可见性
happen-before原则 指令重排 volite修饰变量禁止重拍
有序性
并发出现问题的根本原因
JUC包
并发编程
broker topic
核心组件
Kafka
NameServer无状态
顺序写 随机读 commitlog文件 文件簇
高可用IO
不处理消息重复问题
核心理念
producer
comsumer
NameServer
Broker
topic tag
1.NameServer启动
2.Broker启动 向NameServer注册信息
3.创建topic
4.生成者启动 注册信息并从NameServer拿到路由 往queue写入信息
5.消费者启动 注册信息并从NameServer拿到路由 从queue消费信息
RocketMQ
重发 ack 手动提交偏移量
2pc最终一致性 或 重发 ack 手动提交偏移量
消息的可靠性/一致性
消息在不同分区是没有顺序的
原因
同一分区有 顺序的偏移量 指定分区号 或业务key
同一队列中消息是有序的 RocketMQ提供顺序消息
消息的顺序性
消息表 redis redission分布式锁
消息重复消费
ISR列表选主
主从交叉备份
Broker集群模式
消息刷盘 同步 异步
Broker高可用
路由注册
路由淘汰
路由发现
NameServer高可用
主从交叉存储
同步 异步
消息刷盘
Borker高可用
同步 异步 单向
多种消息发送机制
消息重发
producer高可用
消费失败 重试机制
主从都可消费
consumer高可用
生产者 消费者模型
是先存内存还是先存磁盘 存磁盘不可能存到同一个文件 如何切分存储
存内存还是硬盘
消息的存储
加一些元数据:消息的偏移量 唯一id
对存储的消息进行管理
分片存储
多个节点 怎么存储数据
同步异步
主从同步的规则 节点容错选主
分布式架构
消息的一致性
消息重复消费问题
如何自己设计一个消息中间件
消息中间件
目标类必须实现接口 代理类实现该接口方法 方法目标类独有 接口没有 代理失效
JDK动态代理
生成目标类子类 重写目标类方法
Cglib动态代理
1.引入包 spring-aspect aop
计算器加减乘除接口类 及其实现类
2.目标接口及其实现类
@Aspect @Compant @before前置注解加表达式extention 定位method
extention(public int com.xxxx.pojo.*)
3.切面类
@Configurate @CompantScan
4.配置类
调用目标类 会走代理类方法
5使用
AOP注解实现日志记录
AOP
将开启事务 回滚搞成切面类的前后置通知 织入 目标对象的curd
对数据库事务的封装
TranscationTeplete 硬编码
编程式事务
方法加@Transcational handle()(转账+扣钱) 将开启事务 回滚给spring通知处理
声明式事务
TranscationManager TranscationStatue PlamtFomeTranscationManager
事务管理器
如何实现
过期就回滚
超时时间
事务中的操作只有查询
只读
事务嵌套发生 默认机制requeied A()调b() A()有事务b()加入事务 无事务b()开启事务
传播机制propagation
脏读 不可重复读 幻读
读未提交 读已提交 可重复读 串行化
隔离级别isolation
@Transcation
动态代理做不了
非pubilic方法
多线程
没有走ioc容器
this.xx()调用
事务失效
构造函数实例化 DI属性值及引用属性注入 执行init-method方法 使用 执行destory方法
过程中提供啦很多钩子方法 BeanPostProcess 在init-method前后定制代码 awer接口
生命周期
A实例化 要注入属性B getBean从IOC容器拿 没有要实例化B B又要注入A 死循环
A B相互依赖
实例化后就可以被引用 不需要到初始化那一步 利用缓存提前暴露 没有初始化完成不能放IOC
解决方案
循环依赖
BeanFactory 生产Beand的工厂 IOC容器的顶层接口
FactoryBean 实例化配置Bean的接口 有70多少个实现
BeanFactory FactoryBean
Bean
MVC
jdk byname找
@Resource
spring byttype找 制定名称用Quelifite
@AutoOverride
注解
@AutoWrite 根据类型bytype @qulitze @Resoure byname
同一个类型 有多个实现类 怎么注入
Spring
1.@SpringBootApplication 封装啦3个注解 @SpringBootConguration @EnableAutoConfiguration @CompentScan
2.自动装配的核心是@EnableAutoConfiguration 通过@import导入配置选择器 读取本项目和第三方jar的class path路径下的spring.factory
3.此文件有jar所有配置类的全类名 将配置类的配置bean 通过ConditonOnClass等注解 有条件的注入IOC容器中
自动装配
1.new SpringBootAplication 从spring.foctory找到初始化器 监听器配置 并赋值 初始化器的ininter()会在prepareContext执行 监听器onApplicationEvent方法会在监听到感兴趣的事件后执行
2.执行run() 首先用广播器发布开始事件 创建ConfigurationApplicationEnriment 创建应用环境 ConfigurationApplicationContext 创建应用上下文 作为返回值
3.prepareContxet执行初始化器 refreashContext实例化bean 可以通过BeanPostProcess在Bean实例化前后增加处理代码
4.广播器发布结束事件
main()方法的执行流程
SpringBoot
1.获取Sqlsession对象
获取的是代理对象
2.获取mapper接口
3.执行查询
关联查询
查询主对象时 为关联对象设置代理对象 拦截方法调用 在需要时执行真正的查询
延时加载原理
一级缓存作用在seesion
二级缓存作用域在namespace 和mapper
一级二级缓存
数据搞成list mapper文件foreach标签遍历
批量操作
sql的条件判断
加\"\" 传过来的值都当成字符串 $()不加 有sql注入危险
#{} ${}
动态SQL
MyBatis
框架
数组 链表 红黑数
实现原理
根据key计算Hashcode 根据hashcode得到下表 存在就判断是树节点还是链表 树节点加在树节点上 链表就尾插 达到阈值8就转为红黑树
put流程
不设置默认是16 设置24就是最近往上的2的幂 扩容阈值因数默认0.75 大于阈值是扩容2倍
扩容机制
hash扰动函数 拉链法 冲突过多大于8会转为红黑树 优化查询性能
怎么避免/解决Hash冲突
因为头插法 会颠倒链表顺序 扩容是多线程抢占会链表循环 查数据会遍历链表 会死循环
1.7 hashmap多线程的死循环问题
HashMap
动态数组实现
不设置默认10 超过数组大小 扩容1.5倍
Arrylist
双向链表实现
根据下标离头尾那边近 判断从头尾哪边查
get
LInkList
jdk1.7 分段数据加链表实现
jdk1.8 数据链表红黑树
HashSet
TreeSet
常见集合
Feign集成ribbin resttemplte实现啦负载均衡的http调用
OpenFeign是springcloud对feign的封装 支持SpringMVC的@RequestMapping 对应Feign的RequestLine 通过动态代理创建实现类 实现负载均衡的Http调用
openfeign 服务调用
RequestRateLimit 可以设置令牌桶大小和生成令牌速度
以固定速率生成令牌 请求拿到令牌放行
令牌桶算法
一个路由 由一个id 一个url 多个断言 多个filter组成
访问gateway前 用nginx做负载均衡 实现gateway的高可用
用keepalive+ngnix实现nginx的高可用
高可用
gateway网关
1.引入nacos-dicovery依赖 2.配置文件配置地址端口 3.启动类加注解@EnableDiscoveryClieant
怎么做的
集群
避免单点过载
负载均衡
rafa算法选主
容错机制
监控告警
Nacos服务注册
openfeign发起远程调用就会用负载均衡 ribbin从nacos拉取服务
实现流程
轮训 随机 最小连接数 hash
策略
实现Irun接口 配置文件配置
自定义
ribbin负载均衡
1s内 至少10个请求 至少1个异常 断路器open 熔断10s 10s后半开发个请求 成功断路器关闭
Sentinel/Hysixz服务熔断
微服务
new 子类调父类 反射 main()方法的类
类加载时机
通过类的全类名获取二进制字节流
将字节流代表的静态存储结构换成方法区的运行数据结构
堆内存中新建Class对象 作为方法区数据的访问入口
1.加载
安全验证
1.验证
给staic变量分配空间+赋0值
2.准备
符号引用改为地址引用
3.解析
2.链接
执行clinit() 给类变量赋值
3.初始化
类加载过程
启动类加载器 扩展类加载器 应用类加载器 自定义加载器
安全
双亲委派机制
类加载器
类加载机制
类实例 数组
堆
运行时常量池
栈
运行时数据区
每个线程的工作内存 有多个栈帧 只有一个活动栈帧 提供当前运行方法的内存(包含变量信息)
虚拟机栈
本地方法栈
程序计数器
直接内存
类结构 方法信息 类加载器 逻辑上是堆的一部分 也是线程共享区域
元空间/方法区
本地内存
eden s0 s1
年轻代
老年代
组成
标记清除
标记整理
复制
采用复制算法
新生代回收
并发标记
混合收集
分三步
G1垃圾回收器
只要能被GC root找到 就不会回收
强引用
配合SoftRefrence使用 多次垃圾回收 堆内存不足 就会回收
软引用
配合weakRefrence使用 只要垃圾回收发生 就会回收
弱引用
配合队列使用
虚引用
引用
新建的对象放在edan区 垃圾回收后 幸存的放在s0 s1 多次没回收掉的放在老年区
分代回收
垃圾回收算法
jmap
jstack
工具及命令
系统决定数组长度
String[] s = new String(){'sds'.'sfssf'}
静态初始化
显式指定长度 是引用类型 赋值null
String[] s = new String()[4]
动态初始化
数组在内存中如何分配
栈内存溢出
堆内存溢出
线程过多
1.top 找进程 2. ps -eo grep 查找进程中的线程信息 3. jstack命令 查看进程内线程的详细信息定位代码
cpu占用过高的排查思路
Jvm
http ftp协议
应用层
tcp没有消息边界保护 加分隔符
Frame(tag01111110...)
tcp udp
传输层
网络层
数据链路层
物理层
TCP/IP
表示层
会话层
ISO
网络编程
V-on
V-if
V-show
V-text
V-route
指令
组件
常见面试题
Vue
hashmap的数据结构做啦优化
lamda表达式简化啦代码
jdk1.8的新特性
Java面试题
0 条评论
回复 删除
下一页