# 52. 上下文切换优化分析
# 标准答案
✅ 减少上下文切换的优化策略:
线程优化:
- 合理设置线程数
- 使用线程池
- 避免线程饥饿
- 控制任务粒度
锁优化:
- 减少锁粒度
- 使用无锁数据结构
- 避免锁竞争
- 优化锁持有时间
算法优化:
- 批量处理
- 异步处理
- 任务分片
- 数据本地化
# 答案解析
# 1️⃣ 线程池优化
public class OptimizedThreadPool {
private final ThreadPoolExecutor executor;
public OptimizedThreadPool() {
int coreSize = Runtime.getRuntime().availableProcessors();
executor = new ThreadPoolExecutor(
coreSize,
coreSize,
0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(1000),
new ThreadPoolExecutor.CallerRunsPolicy()
) {
@Override
protected void beforeExecute(Thread t, Runnable r) {
// 设置线程优先级
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
// 设置线程亲和性
setThreadAffinity(t);
}
};
// 预热线程池
warmUpThreadPool();
}
private void warmUpThreadPool() {
for (int i = 0; i < executor.getCorePoolSize(); i++) {
executor.submit(() -> {
// 预热任务
Thread.yield();
});
}
}
private void setThreadAffinity(Thread thread) {
// 设置CPU亲和性,减少跨CPU调度
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 2️⃣ 批量处理优化
public class BatchProcessor {
private static final int BATCH_SIZE = 1000;
private final BlockingQueue<Task> taskQueue;
private final ExecutorService executor;
public void processTasks() {
List<Task> batch = new ArrayList<>(BATCH_SIZE);
while (true) {
// 批量获取任务
taskQueue.drainTo(batch, BATCH_SIZE);
if (batch.isEmpty()) {
break;
}
// 批量处理
executor.submit(() -> {
try {
processBatch(batch);
} finally {
batch.clear();
}
});
}
}
private void processBatch(List<Task> tasks) {
// 分组处理
Map<String, List<Task>> groups = tasks.stream()
.collect(Collectors.groupingBy(Task::getType));
// 并行处理各组任务
groups.forEach((type, groupTasks) -> {
// 一次性获取所需资源
try (ResourceHolder resources = acquireResources(type)) {
// 批量处理
processTaskGroup(groupTasks, resources);
}
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 常见误区
- ❌ 误区1:盲目增加线程数
- ❌ 误区2:过度细粒度拆分
# 典型场景与解决方案
# ✅ 消息处理优化
public class MessageProcessor {
private final int batchSize;
private final DisruptorQueue<Message> queue;
public void processMessages() {
// 使用Disruptor避免锁竞争
queue.consumeBatch(batchSize, messages -> {
// 对消息进行分组
Map<String, List<Message>> groups =
groupMessages(messages);
// 并行处理各组消息
groups.forEach((topic, topicMessages) -> {
processMessageGroup(topicMessages);
});
});
}
private void processMessageGroup(List<Message> messages) {
// 一次性申请资源
try (MessageProcessor.Context ctx = createContext()) {
// 批量处理
for (Message msg : messages) {
ctx.process(msg);
}
// 一次性提交
ctx.commitAll();
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 企业实战经验
# Situation(业务背景)
消息处理系统上下文切换频繁,性能下降。
# Task(核心任务)
优化系统减少上下文切换。
# Action(解决方案)
- 实现批量处理
- 优化线程模型
- 使用无锁队列
- 数据本地化处理
# Result(结果)
- 上下文切换减少70%
- 吞吐量提升200%
- CPU利用率优化
# 深入追问
🔹 如何监控上下文切换?
- 使用vmstat工具
- 监控线程状态
- 分析CPU使用率
🔹 如何选择合适的批处理大小?
- 考虑延迟要求
- 评估内存占用
- 测试不同配置
# 相关面试题
- 上下文切换的成本是什么?
- 如何避免伪共享问题?
- CPU缓存对性能的影响?