一、线程池(ThreadPoolExecutor)
1.线程池解决的不是多线程,而是系统稳定性
不用线程池的本质风险:
- 线程 = JVM +OS资源(栈内存、TCB)
- new Thread()是无上限的资源申请
- 高并发下,频繁上下文切换,系统load飙升,最终OOM / Full GC / 服务雪崩
线程池可以在吞吐量、响应时间、资源消耗之间做平衡
2.ThreadPoolExecutor 内部结构(不是参数层)
2.1 内部三要素
1. Worker(线程封装)
2. ctl(原子状态 + 线程数)
3. 阻塞队列(任务容器)
2.2 ctl
AtomicInteger ctl;
// 高 3 位:线程池状态
// 低 29 位:线程数量
2.3 线程池状态流转
RUNNING → SHUTDOWN → STOP → TIDYING → TERMINATED
2.4 shutdown() 和 shutdownNow() 的区别
- shutdown:不接新任务,执行完队列
- shutdownNow:中断线程,丢弃队列
2.5 线程池核心参数
ThreadPoolExecutor(
corePoolSize, //核心线程数
maximumPoolSize, //最大线程数
keepAliveTime, //非核心线程存活时间,超时没调用就释放
TimeUnit, //超时单位
BlockingQueue<Runnable>, //任务队列
ThreadFactory, //线程工厂
RejectedExecutionHandler //拒绝策略
)
3.任务提交流程
execute(Runnable command)
精准流程:
- workerCount < corePoolSize -> 创建核心线程
- 否则进入队列workQueue.offer
- 如果队列满了,workerCount < max ,创建非核心线程
- 如果仍然失败,触发拒绝策略RejectedExecutionHandler
注意:核心线程默认不回收
4.队列选型
| 队列 | 特点 | 场景 |
|---|---|---|
| ArrayBlockingQueue | 有界 | 稳定流量 |
| LinkedBlockingQueue) | 可无界 | 不可高并发 |
| SynchronousQueue | 不存任务 | CachedThreadPool |
| PriorityBlockingQueue | 优先级 | 调度系统 |
5.线程池参数怎么“算”
5.1 CPU密集型
线程数 ≈ CPU 核数 + 1
5.2 IO密集型
线程数 ≈ CPU * (1 + IO/CPU)
线上的线程池问题大部分都是因为无界队列 + 默认拒绝策略引起的
二、四大函数式接口
1.函数式接口真正的价值
把行为当成参数传递
2.Consumer - 副作用执行者
消费数据
void accept(T t)
- 无返回值
- 通常用于:日志、IO、更新状态
3.Supplier - 延迟对象创建
生成数据
T get()
常用于:
- 缓存懒加载
- 对象池
- 默认值提供
4.Function - 转换器
R apply(T t)
- map的底层
- DTO <-> VO转换核心
5.Predicate - 条件抽象
判断
boolean test(T t)
- filter的本质
- 策略模式 + 责任链
示例:
Supplier<String> s = () -> "hello";
Consumer<String> c = System.out::println;
Function<Integer, String> f = i -> "num:" + i;
Predicate<Integer> p = i -> i > 10;
6.函数式接口 vs if-else
- if-else是控制流
- 函数式接口是数据驱动
三、Stream流式计算
1.Stream不等于forEach简写
Stream 执行模型:
Source → Intermediate Ops → Terminal Op
延迟执行原理:
- 中间操作不执行
- 终止操作触发整个链路
2.内部原理
Spliterator + Pipeline
- 拆分数据
- 串联操作
- 一次遍历完成
3.为什么stream不能复用
状态被消费,和iterator类似
示例:
list.stream()
.filter(x -> x > 10)
.map(x -> x * 2)
.collect(Collectors.toList());
4.特点
- 懒惰执行
- 不存储数据
- 不可复用
- 内部迭代
5.并行流
list.parallelStream()
- 使用ForkJoinPool.commonPool
- 不适合I/O
- 线程安全问题
6.应用场景
- 数据过滤、统计
- 聚合分析
- 报表计算
四、ForkJoin & 异步回调(CompletableFuture)
1.ForkJoin 框架
核心思路:分治
RecursiveTask<V>
RecursiveAction
- 工作窃取(Work-Stealing)
- 适合CPU密集型任务
2.CompletableFuture
CompletableFuture.supplyAsync(() -> queryDB())
.thenApply(data -> convert(data))
.thenAccept(System.out::println)
.exceptionally(e -> null);
1.常见API
- thenApply(转换)
- thenAccept(消费)
- thenCombine(合并)
- allOf / anyOf
2.应用场景
- 并行RPC
- 异步聚合接口
- 提升接口RT
五、泛型
1.作用
- 类型安全
- 消除强转
- 提升可读性
2.泛型边界
<T extends Number>
<T super Integer>
PESC原则
Producer Extends,Consumer Super
3.类型擦除
- 编译期泛型
- 运行期被擦除
- 通过反射无法获取泛型真实类型(除非父类)
4.应用场景
- 集合
- DAO层
- 通用返回体
六、反射
1.作用
- 创建对象
- 调用方法
- 操作字段
- 读取注解
Class<?> clazz = Class.forName("User");
Object obj = clazz.getDeclaredConstructor().newInstance();
优点:动态、解耦
缺点:性能差、不安全
场景:Spring IOC、AOP、ORM框架(mybatis)
七、枚举
1.本质
- enum是final class
- 每个枚举是单例
2.枚举 + 策略模式
enum OrderStatus {
CREATED { void handle() {} },
PAID { void handle() {} }
}
场景
- 状态机
- 错误码
- 常量代替
总结
1.为什么不推荐 Executors?
内部线程数或队列无界,存在 OOM 风险,生产环境应自定义线程池。
2.Stream 和 for 循环区别?
Stream 是声明式、惰性执行、支持并行,但调试性较差。
3.CompletableFuture 和 Future 区别?
Future 只能阻塞 get,CompletableFuture 支持回调、组合、异常处理。
4.泛型为什么运行期不可见?
Java 使用类型擦除实现泛型,保证向下兼容。
5.枚举为什么线程安全?
JVM 保证枚举实例在类加载阶段初始化,天然单例。
1374



被折叠的 条评论
为什么被折叠?



