上下文切换及线程操作相关内容

发布于:2025-08-19 ⋅ 阅读:(13) ⋅ 点赞:(0)

一、上下文切换深度解析

1. 切换过程拆解
暂停线程A
保存A的上下文
'PC+寄存器值'
加载线程B的上下文
恢复B的执行位置
2. 性能影响关键点
  • 直接开销
    • 寄存器保存/恢复:约1000-3000时钟周期
    • TLB缓存失效:导致内存访问延迟增加
  • 间接开销
    • CPU缓存命中率下降(新线程数据未缓存)
    • 调度器计算消耗(如CFS调度器的红黑树调整)
3. 优化策略
// 减少切换的编码实践
1. 避免过度创建线程(使用线程池)
2. 减小临界区范围(同步代码块最小化)
3. 使用无锁数据结构(如ConcurrentHashMap

二、线程创建方式对比

1. 无返回值实现
方式 示例代码 优缺点
继承Thread class MyThread extends Thread 简单但Java单继承限制
实现Runnable new Thread(() -> {}).start() 推荐方案,灵活组合
2. 带返回值实现
// Callable + FutureTask 示例
Callable<Integer> task = () -> {
    TimeUnit.SECONDS.sleep(1);
    return 42;
};
FutureTask<Integer> future = new FutureTask<>(task);
new Thread(future).start();
System.out.println(future.get()); // 阻塞获取结果

三、线程中断机制详解

1. 中断流程
阻塞中
运行中
ThreadA调用threadB.interrupt方法
设置threadB的中断标志位
threadB检查中断
抛出InterruptedException
自行处理标志位
2. 正确中断实践
// 标准中断处理模板
public void run() {
    while (!Thread.currentThread().isInterrupted()) {
        try {
            // 业务代码
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            // 恢复中断状态(避免吞没中断)
            Thread.currentThread().interrupt();
            break;
        }
    }
}

四、volatile与锁的对比

1. volatile适用场景
  • 单写多读:如开关标志位
    private volatile boolean running = true;
    
  • 禁止重排序:DCL单例模式
    private static volatile Singleton instance;
    
2. 锁的选择策略
锁类型 特点 适用场景
synchronized JVM内置,自动释放 简单同步需求
ReentrantLock 可中断、公平锁、条件变量 复杂同步控制
StampedLock 乐观读锁 读多写少的高性能场景

五、CompletableFuture进阶

1. 核心方法速查
方法 作用 异步示例
supplyAsync() 带返回值的异步任务 supplyAsync(() -> "result")
thenApply() 结果转换 .thenApply(s -> s.length())
thenCombine() 合并两个任务结果 future1.thenCombine(future2, (a,b) -> a+b)
exceptionally() 异常处理 .exceptionally(ex -> "fallback")
2. 超时控制最佳实践
CompletableFuture.supplyAsync(() -> {
    // 长时间任务
    return fetchData();
}).get(2, TimeUnit.SECONDS); // 抛出TimeoutException

六、生产环境问题排查

1. 线程状态诊断命令
jstack <pid> | grep -A 1 "java.lang.Thread.State"  # 查看线程状态分布
jcmd <pid> Thread.print                            # 完整线程转储
2. 常见死锁模式
// 典型的交叉锁死锁
Thread1: 锁定A后尝试获取B
Thread2: 锁定B后尝试获取A

通过jstack输出的Found one Java-level deadlock可快速定位。