java面试知识点复习

集合:

复制代码
ArrayList 和 LinkedList 区别
ArrayList:数组结构,查询快,增删慢,线程不安全
LinkedList:双向链表,增删快,查询慢, 线程不安全

ArrayList: 为什么线程不安全?
不具备原子特性, 没有锁,没有CAS
解决方案:
1. Collections.synchronizedList   同步包装类    原理:包装类,所有方法加 synchronized, 并发性能一般
2.  CopyOnWriteArrayList     原理: 修改(add/set/remove)时加锁,ReentrantLock ,先复制出新数组,修改新数组,改完再替换引用 , 读无锁  写加锁
3.  业务层手动加锁 使用同步方法操作list(synchronized / ReentrantLock)

HashMap 底层原理

复制代码
1. 底层结构
数组 + 单向链表 + 红黑树 :   hash冲突少的时候  挂链表, 冲突多的时候链表过长(链表长度 ≥8 并且数组容量 ≥64 ),转为红黑树()
2. 线程不安全, 没有加锁、没有 CAS,复合操作不保证原子性  
并发方案请使用 ConcurrentHashMap

ConcurrentHashMap底层原理

复制代码
底层结构:  数组 + 链表 + 红黑树,和 HashMap 结构一致。
核心并发保障:   采用:CAS + synchronized 细粒度锁
和Hashtable相比 :Hashtable 全局 synchronized 锁,锁整张表,并发极低

锁:

锁分类

复制代码
可重入锁 :  同一个线程多次获取同一把锁不会阻塞
公平锁、非公平锁
独占排他锁、读写共享锁;


synchronized专享,锁升级
偏向锁:单线程无竞争,无加锁开销
轻量级锁:少量竞争,自旋 CAS(Compare And Swap,比较并交换)
重量级锁:竞争激烈,阻塞 + 内核态
锁只能升级,不能降级

锁: synchronized

复制代码
Java 内置隐式锁,JVM 层面实现
用来保证原子性、可见性、有序性,解决多线程并发竞争问题。
三大特性
原子性:同一时刻只有一个线程执行临界区代码
可见性:锁释放时刷新主内存,其他线程立刻可见最新值
有序性:禁止指令重排序
volatile 只能保证可见性和有序性,不能保证原子性


可用来
修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁(锁的是 当前对象 this)
修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象(Class对象)的锁

Lock锁(JUC 锁)

复制代码
Lock 是 Java 代码层面显式锁,手动加锁、手动解锁,功能比 synchronized 强很多。

ReentrantLock 可重入独占锁(最常用)
ReentrantReadWriteLock 读写锁 (包含ReadLock 共享读锁,和WriteLock 独占写锁)
StampedLock 乐观读锁(JDK8 新)

核心方法有:
void lock(); // 加锁,拿不到一直等
void unlock(); // 释放锁
boolean tryLock(); // 尝试拿锁,拿不到直接返回false
boolean tryLock(long time, TimeUnit unit); // 限时等待
void lockInterruptibly(); // 可被中断的等待
Condition newCondition(); // 绑定条件队列


底层核心:AQS 抽象队列同步器
所有 JUC Lock 底层全部依赖 ,   AQS全称:AbstractQueuedSynchronizer
AQS核心:
AQS 核心:
一个 volatile 修饰的 state 状态变量 控制加锁释放
一个 双向 FIFO 阻塞队列 存放抢不到锁的线程
底层大量 CAS + 自旋 抢锁

Redis 分布式锁

复制代码
Redis 分布式锁,使用Redisson 实现;
多个实例,只允许少量获取锁,使用分布式信号量(Redisson RSemaphore)

Redis 分布式锁 实现步骤(4步)
1. SET NX EX 加锁(互斥 + 防死锁)
2. value 设唯一值(防止误删)
3. Lua 脚本删锁(原子操作)
4. 看门狗自动续期(防止业务没跑完锁失效)

线程池:

复制代码
线程池七大参数:核心线程数、最大线程数、空闲存活时间、时间单位、阻塞队列、线程工厂、拒绝策略。
执行流程:先创建核心线程,核心满了任务进阻塞队列,队列满了扩容到最大线程数,线程打满队列也满走拒绝策略。
参数配置分 :
CPU 密集设 CPU 核心数 + 1,
IO 密集设 CPU 核心数 2 倍左右;
队列用有界队列防止 OOM,
拒绝策略业务常用调用者运行策略。



阻塞队列:  
ArrayBlockingQueue:有界队列(推荐)
LinkedBlockingQueue:无界 / 有界,无界会 OOM

拒绝策略:
任务太多、队列满、线程开到最大,再也接不住了:
AbortPolicy 默认:直接抛异常
CallerRunsPolicy 调用者自己跑任务(常用,也就不在接收线程)
DiscardPolicy 直接丢弃任务,不报错
DiscardOldestPolicy 丢掉队列最老任务,加新任务



为什么禁止用 Executors 创建线程池:
Executors 底层封装的线程池,要么队列无界导致 OOM,要么最大线程数无上限导致线程爆炸、CPU 飙高

Spring 事务传播机制

复制代码
Spring 一共 7 种 传播级别
1. REQUIRED(默认)最常用: 有事务就加入,没事务就新建
	外层有事务:内层加入同一个事务
	外层没事务:内层新建一个事务
2. SUPPORTS 有事务就跟着走,没事务就非事务运行
	外层有事务:加入
	外层没事务:不开启事务,裸跑
3. MANDATORY  强制要求必须在事务里运行
	外层有事务:正常执行
	外层没事务:直接抛异常
4. REQUIRES_NEW 不管外面有没有,永远新建独立事务
	外层有事务:先挂起外层,自己新开一个独立事务
	内层事务互不影响,内层回滚不影响外层,外层回滚不影响内层
5. NOT_SUPPORTED 永远以非事务方式运行
	不管外层有没有事务,都挂起事务,裸跑
6. NESTED 嵌套事务   有事务就嵌套在当前事务的保存点里,没事务就新建
	外层有事务:内层是子事务 / 保存点
	内层回滚不影响外层,外层回滚连带内层一起回滚
	外层没事务:自己新建事务
7.  NEVER 强制非事务
	外层没事务:正常跑
	外层有事务:直接抛异常

Spring 事务隔离级别

复制代码
数据库原生的 4 种隔离级别 + 1 个 Spring 专属默认级别
读未提交:能读到别人未提交的数据
读已提交:只能读已提交数据,解决脏读,不可重复读和幻读还有;
可重复读:MySQL 默认,解决脏读、不可重复读,仍有幻读;
串行化:最高级别,全部问题都解决,但是性能最差;
DEFAULT:Spring 默认,跟随底层数据库自带隔离级别


脏读:   一个事务内读到了另一个事务未提交的数据
幻读:   同一个事务内,读到的行数不一样
不可重复读:  同一个事务内,两次结果不一样

JVM的类加载机制是什么

复制代码
双亲委派机制 类加载器会先让自己的父类来加载,父类无法加载的话,才会自己来加载
①如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行;
②如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器;
③如果父类加载器可以完成加载任务,就成功返回,倘若父类加载器无法完成此挤在任务,子加载器才会尝试自己去加载,这就是双亲委派模式。
在这里插入代码片


tomcat是如何破坏双亲委派的
自定义多层类加载器,并让每个 Web 应用拥有独立的 WebAppClassLoader,重写 loadClass 方法把加载顺序从 "先父后子" 改成 "先子后父"
同时对 java.*、org.apache.catalina.* 等核心包仍走双亲委派,保证安全。

数据库基础:

复制代码
1. 事务四大特性 ACID
原子性:要么全成功,要么全回滚
一致性:事务前后数据完整性一致
隔离性:事务之间互不干扰
持久性:提交后数据永久落地,宕机也不丢

2. 事务三大问题
脏读:读到别人未提交数据
不可重复读:同一事务两次查同一条,结果不一样
幻读:同一事务范围查询,别人新增 / 删除,条数变了

3. 四大隔离级别
读未提交:都存在
读已提交:解决脏读,不可重复、幻读还有
可重复读:MySQL 默认,解决脏读、不可重复读,有幻读
串行化:全部解决,性能最差

数据库进阶

复制代码
4. 索引底层结构
InnoDB 索引是 B + 树(B+树, 矮胖、磁盘 IO 少、适合范围查询、排序)
B + 树是多路平衡查找树, B + 树核心特点
	矮胖、分叉多:节点存很多键,树高很小(通常 2~4 层),磁盘 IO 极少。
	数据全在叶子:内部节点只做索引,查询必须走到叶子。
	叶子有序链表:范围查询、排序、分页极快。
	平衡:插入删除自动维持平衡,查询稳定 O (log n)。


5. 索引失效场景
	模糊查询 %开头
	索引列做运算、函数、类型转换
	or 条件有非索引列
	违背最左前缀
	数据量太少、区分度太低
	隐式类型转换
	
6. 慢查询优化步骤
	开启慢查询日志
	explain 分析执行计划
	看有没有全表扫描、临时表、文件排序
	加合适索引、避免索引失效
	拆分大 SQL、分页优化
	
7. explain 重点字段
	type:all 全表扫描最差,range、ref、eq_ref 越好
	key:实际用到的索引
	rows:扫描行数越少越好
	Extra:Using filesort、Using temporary 要优化

springBoot的核心注解

复制代码
@SpringBootApplication 
其实它是三个注解的合体
1.@SpringBootConfiguration
	标记这是一个配置类(本质就是 @Configuration)。
2.@EnableAutoConfiguration
	SpringBoot 最核心功能:自动配置
	帮你自动配好 Tomcat、SpringMVC、MyBatis、Redis 等,不用写 XML。
3. @ComponentScan
	自动扫描包,扫描当前包及其子包下的 @Controller、@Service、@Repository 等,注册成 Bean。
相关推荐
小程故事多_801 小时前
[大模型面试系列] 破解 Agent 软故障困局,四层防御 + 可观测性,筑牢生产级稳健性防线
人工智能·面试·职场和发展·智能体
郭涤生1 小时前
std::condition_variable的使用及主要事项
开发语言·c++
小菜鸡桃蛋狗1 小时前
C++——list
开发语言·c++
hopetomorrow2 小时前
学习路之PHP --PHP 常用扩展及作用表
开发语言·学习·php
信徒_2 小时前
API 网关技术选型
java
simple-L62 小时前
Java开发痛点技术文章大纲
java·开发语言
嵌入式小企鹅2 小时前
嵌入式面试宝典
学习·面试·嵌入式·嵌入式工程师·高薪offer
m0_635647482 小时前
Qt打包含有第三方库的软件为应用程序——CQtDeployer
开发语言·数据库·qt
simple-L62 小时前
Vue3 前端开发技术文章大纲
开发语言