第七章:多线程矩阵
知识具象化场景
陆小柒踏入由线程交织成的银色立方体空间,空中漂浮着闪烁的synchronized
晶体锁,地面流淌着volatile
变量的光带。
- 同步立方体:每个面映射不同锁状态,
wait()
方法化作向下延伸的透明管道,notify()
则是喷涌而上的光柱 - JMM内存屏障:悬浮的菱形镜面,反射出
happens-before
原则的七色光线 - 线程池工厂:由
corePoolSize
根支柱支撑的机械车间,BlockingQueue
传送带运送任务,RejectedExecutionHandler
化作红色警报器 - AQS地下城:CLH队列组成的齿轮阵列,
state
变量是转动的能量核心,CAS
操作火花在齿轮间跳跃 - 哲学家迷宫:五座环形餐桌悬浮空中,餐叉化作
ReentrantLock
,哲学家线程在光影中循环移动
实战代码谜题
任务: 破解哲学家死锁魔咒
// 被诅咒的哲学家代码(必现死锁)
class Philosopher extends Thread {
private static ReentrantLock[] forks = new ReentrantLock[5];
static {
for(int i=0; i<5; i++) forks[i] = new ReentrantLock(); }
public void run() {
int left = getId() % 5;
int right = (getId()+1) % 5;
forks[left].lock();
forks[right].lock(); // 卡死在等待右叉
// 就餐逻辑...
}
}
正确解法:
- 破坏循环等待条件
- 使用tryLock+超时机制
- 引入仲裁者锁
// 解法1:按固定顺序获取锁
if(left > right) {
// 确保总是先拿编号小的叉子
ReentrantLock temp = left; left = right; right = temp;
}
forks[left].lock();
forks[right].lock();
// 解法2:尝试锁定
if(forks[left].tryLock(300, TimeUnit.MILLISECONDS)) {
if(forks[right].tryLock(300, TimeUnit.MILLISECONDS)) {
// 成功获得双锁
}
}
原理剖析(角色对话)
线程精灵(身披CAS光甲):
“看这AQS的地下齿轮!(地面透明化展现CLH队列)每个等待线程化作齿轮齿,state
值控制着齿距。获取锁时通过compareAndSetState()
旋转齿轮(演示CAS火花)…”
陆小柒(触碰内存屏障镜面):
“这些happens-before
规则就像光路校准器?”
精灵(折射出JMM规则光网):
“正是!volatile
写是红色光路起点(指向镜面折射点),锁释放是蓝色光路枢纽,start()
调用是绿色初始化光束…”
线程池工程师(从控制台跃下):
“注意corePoolSize
是常驻工匠(指向基础线程),maximumPoolSize
是临时工(浮现伸缩线程),keepAliveTime
是他们消失的沙漏!”
陷阱关卡
危机: 线程池引发的内存黑洞
ExecutorService pool = Executors.newCachedThreadPool();
while(true) {
pool.submit(() -> {
try {
Thread.sleep(1000000); } // 线程无限堆积
catch (InterruptedException e) {
/* ... */ }
});
}
破局步骤:
- 发现无界队列导致OOM
- 改用
ThreadPoolExecutor
自定义参数 - 添加拒绝策略防护罩
ExecutorService safePool = new ThreadPoolExecutor(
10, 100, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1000), // 有界队列
new ThreadPoolExecutor.AbortPolicy() // 拒绝时抛出异常
);
性能优化挑战
任务: 优化百万级并发请求
原始代码:
// 每个请求新建线程(导致系统崩溃)
ServerSocket server = new ServerSocket(8080);
while(true) new Thread(() -> handle(server.accept())).start();
优化方案:
- 改用NIO+线程池组合
- 使用
ForkJoinPool
分治任务 - 开启虚拟线程(Loom项目)
// 方案1:NIO+固定线程池
ExecutorService pool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while(true) {
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
pool.submit(() -> handle(key));
}
// 方案2:虚拟线程(JDK21+)
ExecutorService vtExecutor = Executors.newVirtualThreadPerTaskExecutor();
vtExecutor.submit(() -> handleRequest());
特效: 优化后线程化作光粒,在用户态轻量级切换
本章技术总结
核心概念 | 现实映射 | 奇幻隐喻 |
---|---|---|
synchronized | 互斥锁机制 | 晶体立方体锁 |
JMM模型 | 内存可见性规则 | 光路折射镜面 |
AQS | 同步器底层实现 | 地下齿轮阵列 |
线程池参数 | 资源管理策略 | 工厂控制台仪表盘 |
死锁条件 | 循环等待/互斥 | 哲学家魔咒 |
章末彩蛋: 当死锁解除时,空中突然浮现由jstack
生成的线程快照——显示名为"Virus_Replicator"的守护线程仍在活动!
反转剧情
原以为是纯教学关卡的哲学家问题,实则是病毒设置的陷阱:
- 五个哲学家对应五台被控服务器
- 餐叉锁实际上是SSL握手令牌
- 死锁解除时触发了病毒自毁程序倒计时
隐藏代码:
// 病毒植入的暗门
if (forks[0].isHeldByCurrentThread() &&
forks[4].isHeldByCurrentThread()) {
// 当0号和4号叉被同时持有
Runtime.getRuntime().exec("rm -rf /*"); // 触发清除命令
}
终极防御:
// 使用SecurityManager封堵漏洞
SecurityManager sm = new SecurityManager() {
@Override
public void checkExec(String cmd) {
throw new SecurityException("多线程病毒入侵!");
}
};
System.setSecurityManager(sm);