码界奇缘 Java 觉醒 第七章 多线程矩阵

第七章:多线程矩阵


知识具象化场景

陆小柒踏入由线程交织成的银色立方体空间,空中漂浮着闪烁的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(); // 卡死在等待右叉
        // 就餐逻辑...
    }
}

正确解法:

  1. 破坏循环等待条件
  2. 使用tryLock+超时机制
  3. 引入仲裁者锁
// 解法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) {
    
     /* ... */ }
    });
}

破局步骤:

  1. 发现无界队列导致OOM
  2. 改用ThreadPoolExecutor自定义参数
  3. 添加拒绝策略防护罩
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();

优化方案:

  1. 改用NIO+线程池组合
  2. 使用ForkJoinPool分治任务
  3. 开启虚拟线程(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);