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