面试题
集合
List
- ArrayList Object[]
- LinkedList 双向链表,尾插
- Vector Object[] 线程安全
- CopyOnWriteArrayList 线程安全 写时复制
Map
- HashMap 可null key,但只一
- <1.8 数组+链表 链表数组,扰动函数得hash值, 拉链法解决哈希冲突
- 1.8 数组+链表+红黑树 哈希冲突时变化: 链表长度小于64扩容,否则转换为红黑树
- 默认16,扩容2n
- Hashtable 线程安全,整体加锁
- ConcurrentHashMap 线程安全,针对
Segment
加锁
多线程
内存泄漏、死锁、线程不安全
-
死锁:互斥、请求与保持、不剥夺、循环等待
-
JMM
- 原子性 synchronized各种Lock
- 可见性 synchronized、volatile
- 有序性 volatile
-
乐观锁和悲观锁:
- 悲观:synchronized
和
ReentrantLock - 乐观:版本号:CAS算法(VEN,可能存在ABA问题则需搭配版本号,Unsafe的JNI)
- 悲观:synchronized
-
synchronized 可重入;重量级锁,非公平、依赖底层moniter;
优化:自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁 -
ReentrantLock 可重入;基于API、可中断、能公平
-
ThreadLocal: 线程特有的
-
线程池ThreadPoolExecutor:
- corePoolSize: 任务队列未达队列容量时最大可以同时运行的线程数量
- maximumPoolSize : 任务队列中达容量时可运行最大线程数
- workQueue: 任务队列
- keepAliveTime: 非核心线程空闲销毁时间
- unit : 时间单位
- threadFactory :executor 创建新线程的时候会用到
- handler: 拒绝策略
JVM
内存布局
- 运行时数据区
- 堆
- 新生代(伊甸园、s0、s1,存活<15)、老年代、永久代(1.8移到元空间)
- 字符串常量池
- 方法区(1.8为元空间,在本地内存)
- 运行时常量池
- 线程数据:虚拟机栈(栈帧:本地变量表、返回地址、操作数栈)、本地方法栈、程序计数器,后入先出
- 堆
- 本地内存
- 元空间(1.8才有,在本地内存)
GC
1、内存在伊甸园分配,不足Minor GC,大对象或仍不足则老年代(分配担保)
2、大对象(字符串或数组)、长期存活(age>=15)
- 死亡判断
引用计数法:无法解决循环引用问题
可达性分析:从**GC Roots(虚拟机栈、本地方法栈、方法区中类静态属性、方法区中常量、同步锁、JNI等引用的对象)**遍历 - 回收算法
标记-清除:耗时且效率不高
标记-复制:解决标记-清除问题,适合新生代
标记-整理:适合老年代(因为耗时而老年代不常回收) - 垃圾收集器
jdk8 Parallel Scavenge(新生代)+ Parallel Old(老年代)新生代采用标记-复制算法,老年代采用标记-整理算法。
jdk9~22:G1
类加载过程
加载->连接(验证->准备->解析)->初始化
- 加载(双亲委派、类加载器):全类名获取二进制数据;将字节流所代表的静态存储结构转换为方法区的运行时数据结构;在内存中生成一个代表该类的Class对象,作为方法区这些数据的访问入口
- 验证:文件格式验证(Class 文件格式检查)、元数据验证(字节码语义检查)、字节码验证(程序语义检查)、符号引用验证(类的正确性检查)
- 准备:分配内存并设置类变量初始值,在方法区分配
- 解析:虚拟机将常量池内的符号引用替换为直接引用的过程
- 初始化:初始化阶段是执行初始化方法
MySQL
数据类型:
TINYINT、SMALLINT、MEDIUMINT、INT 和 BIGINT;
CHAR、VARCHAR、TINYTEXT、TEXT;
YEAR、TIME、DATE、DATETIME 和 TIMESTAMP。
基础架构
连接器:登录(身份认证和权限相关)。
查询缓存:执行查询时先查询缓存(MySQL 8.0 版本后移除)
分析器:检查与分析SQL语句
优化器:优化SQL
执行器:执行语句,从存储引擎返回数据(执行前会判断权限)
插件式存储引擎:负责数据的存储和读取,采用的是插件式架构,支持 InnoDB(默认)、MyISAM、Memory 等多种存储引擎
存储引擎
MyISAM: 表级锁;索引为B+非聚簇;
InnoDB:表级锁;行级锁,及MVCC,索引为B+聚簇,事务,外键,崩溃恢复(redo log),主从(binlog)
MVCC
- 原理:
隐藏列:InnoDB中行隐藏列trx_id(最后一次修改的事务ID,可断事务顺序)、roll_pointer(指向Undo日志的指针,指向历史版本,形成一个链表结构);如无主键及唯一索引则row_id
Undo日志:历史版本
ReadView:实现快照读而创建数据结构,保存了当前未提交事务列表及当前系统最大事务ID,可判断某版本数据对当前事务是否可见;包含:creator_trx_id:创建该ReadView的事务ID,trx_ids:创建该ReadView时活跃(未提交)事务列表,up_limit_id:创建该ReadView时活跃事务列表中最小的事务ID,low_limit_id:当前系统最大事务ID+1 - 快照读算法
根据ReadView和Undo日志来判断某个版本的数据是否对当前事务可见的算法
如trx_id小于ReadView的up_limit_id,说明在ReadView之前就存在,且未更新过,对当前事务可见
如trx_id大等于low_limit_id,创建后才插入或者更新,对当前事务不可见
up_limit_id和low_limit_id之间,但不在ReadView的trx_ids列表中,可见
之间但不在列表中,不可见 - 工作机制:版本链、快照读、写操作
事务特性
原子性(Atomicity)一致性(Consistency,目的)隔离性(Isolation)持久性*(Durability)
隔离级别
读未提交、读已提交(基于MVCC)、可重复读(基于MVCC)、串行化(基于锁)
并发事务问题
脏读:即使事务未提交其它事务仍能读到
不可重复读:一事务未结束时其它事务修改了数据,导致该事务再次读取时结果不一致
幻读:一事务未结束时其它事务插入了数据,导致该事务再次读取时结果不一致
索引类型
数据结构:B+树、hash、红黑树、二叉查找树(BST)
存储方式:聚簇索引(索引和数据合并)、非聚簇索引(索引和数据分开)
应用维度:主键索引、普通索引、联合索引(多列值组成一个索引)、覆盖索引(一个索引包含所有需要查询的字段的值)
最左前缀:使用联合索引时,根据索引中的字段顺序从左到右依次匹配查询条件中的字段,直到范围查询(如 >、<)为止
索引下推:索引优化功能,存储引擎在索引遍历过程中,执行部分WHERE字句的判断条件,直接过滤掉不满足条件的记录,从而减少回表次数
锁分类
表级(非索引加锁)
行级(索引加锁):记录锁(单个行),间隙锁(Gap Lock,范围不包括),临键锁(Next-Key Lock,范围包括,解决幻读)
都分为共享锁和排它锁
InnoDB的可重复读隔离级别默认临键锁,但如是单个索引或主键则退为记录锁
Spring
模块:core beans context expression, aop aspects, jdbc hx orm
核心:IoC, AoP
IoC
控制反转:由Spring来管理Bean的生命周期
生命周期:创建实例、属性填充、初始化(各种Aware接口的依赖注入、BeanPostProcessor在初始化前后的处理、InitializingBean和init-method的初始化操作)、销毁(DisposableBean和destory-method)
AOP
面向切面编程:JDK代理、CGLIB
用途:
日志记录:只需要在 Controller 的方法上使用自定义 @Log 日志注解,就可以将用户操作记录到数据库
限流:利用 AOP 方式对接口进行限流,只需要在 Controller 的方法上使用自定义的 @RateLimit 限流注解即可。利用 Redisson 中的 RRateLimiter 来实现分布式限流,其底层实现就是基于 Lua 脚本+令牌桶算法
事务管理:@Transactional
MVC
工作流程
DispatcherServlet拦截请求
DispatcherServlet根据请求调用HandlerMapping 。
HandlerMapping根据URL匹配Handler(Controller 控制器) ,并封装涉及的拦截器和Handler一起封装后调用HandlerAdapter适配器执行 Handler 。
Handler处理后,返ModelAndView给DispatcherServlet,ViewResolver 会根据逻辑 View 查找实际的View。DispaterServlet把返回的Model传给 View(视图渲染)。把 View 返回给浏览器
统一异常
@ControllerAdvice + @ExceptionHandler(必须Controller或ResponseBody)
事务
管理方式:编程(通过代码)、声明(XML或注解)
传播行为:
PROPAGATION_REQUIRED(必须,加入)、PROPAGATION_REQUIRES_NEW(必须,挂起)、PROPAGATION_NESTED(必须,嵌套)、PROPAGATION_MANDATORY(必须,报错)
PROPAGATION_SUPPORTS(不必须、加入)、PROPAGATION_NOT_SUPPORTED(不必须、挂起)、PROPAGATION_NEVER(不必须、报错)
隔离级别:
ISOLATION_DEFAULT、ISOLATION_READ_UNCOMMITTED、ISOLATION_READ_COMMITTED、ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE
Boot启动过程
SpringApplication索引