信息技术大学
并发编程
计算机基础面试八股 · 第 4 章 编程语言与工程素养
按 空格/→ 演示下一步
全部页面点击任意一页,跳回舞台从这页播放
信息技术大学
并发编程
计算机基础面试八股 · 第 4 章 编程语言与工程素养
竞态条件与临界区
结果取决于执行时序就是竞态:被并发访问的共享数据段就是临界区。
竞态
check-then-act、读改写都是典型窗口
临界区
访问共享资源的代码段,必须互斥执行
原子性
要么全做要么不做,不给并发留缝隙
线程池参数与执行流程
七个参数定一个池:核心数、队列、拒绝策略互相牵制,先想任务类型。
核心参数
corePoolSize、maximumPoolSize、workQueue、拒绝策略
执行流程
核心线程→入队列→扩展线程→拒绝策略
池大小
CPU 密集取核数+1,IO 密集按等待比放大
拒绝策略
Abort 抛异常、CallerRuns 回退、Discard 丢弃
CAS 与原子操作
比较并交换是无锁的根基:期望值还在才替换,失败就重试。
CAS
CPU 原子指令:compare and swap
ABA 问题
值变回原样 CAS 察觉不到,加版本号解决
自旋代价
冲突高时重试烧 CPU,该退回互斥锁
ThreadLocal 思想
不共享就没竞态:每个线程一份私有副本,用完记得 remove。
副本隔离
线程各存一份,互不可见天然无锁
泄漏风险
key 弱引用 value 强引用,线程池必须 remove
死锁排查
卡死先看线程栈:jstack 抓快照,Found one Java-level deadlock 会直接点名。
征兆
线程成对 BLOCKED,业务面停摆
jstack
抓线程栈快照,直接报告互相持等关系
修复
统一加锁顺序、缩小锁范围、超时退出
本节要点
- ✓竞态在时序,临界区须互斥
- ✓线程池先想任务类型再定参数
- ✓CAS 无锁但防 ABA,冲突高退回锁
- ✓ThreadLocal 用完必须 remove
延伸主题:复现一次死锁并排查压测线程池拒绝策略
课后思考
先自己回答,再展开参考答案——能讲出来才算真懂。
1线程池为什么先排队再扩容,而不是先扩到最大线程数?
参考答案队列缓冲复用固定线程,避免瞬时尖峰就创建大批线程;队列满才说明负载持续超容量,再扩到上限,仍不行才走拒绝。顺序是为资源稳定而设计的。
2ThreadLocal 为什么在线程池环境特别容易内存泄漏?
参考答案线程常驻,ThreadLocalMap 就一直在;key 是弱引用可被回收,value 是强引用留在 Map 里成孤儿。线程复用还会读到脏值,所以用完必须 remove。
3CAS 只保证单个变量原子,多变量更新怎么办?
参考答案把多个变量合成一个对象放进 AtomicReference 打包 CAS,或用锁把多变量操作包成临界区。思路都是把多次修改打包成一次原子决策。