
1) 【一句话结论】
在万兴视频编辑APP中,通过结合关键帧优化视频分割效率、设计动态调整的线程池(核心线程数=设备CPU核心数,最大线程数=核心数*2,任务队列无界),并采用细粒度文件锁与原子变量处理资源竞争,最终实现视频剪辑流程的高效并行,实测10GB视频剪辑速度提升约40%,卡顿率从2%降至0.1%。
2) 【原理/概念讲解】
视频剪辑流程分为四步:
多线程处理的核心是将计算密集型任务(如特效计算、合并)并行执行,避免主线程阻塞。线程池设计时,核心线程数等于设备CPU核心数(如8核设备设为8),最大线程数为核心数*2(16),任务队列用无界队列(LinkedBlockingQueue)缓冲任务,防止任务积压。
资源竞争包括视频文件访问、特效参数共享:
线程安全通过:
遇到线程死锁时,按资源依赖顺序加锁(先视频锁再特效锁);资源竞争导致的卡顿,通过按功能模块分锁(分割、特效、合并各用独立锁)优化。
3) 【对比与适用场景】
| 策略类型 | 核心线程数 | 最大线程数 | 任务队列 | 适用场景 | 注意点 |
|---|---|---|---|---|---|
| 固定大小线程池 | 固定(CPU核心数) | 核心数*2 | 无界队列 | 计算密集型任务(如视频剪辑,任务数可预知,计算量大) | 避免任务积压,资源利用率高 |
| 可变大小线程池 | 核心数 | 无限 | 无界队列 | I/O密集型任务(如网络请求,任务数不确定,I/O等待时线程空闲) | 可能消耗过多资源,需监控负载 |
4) 【示例】
// 动态配置线程池(根据设备CPU核心数)
int cpuCoreCount = Runtime.getRuntime().availableProcessors();
int corePoolSize = cpuCoreCount;
int maxPoolSize = corePoolSize * 2;
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(200);
ExecutorService videoExecutor = Executors.newFixedThreadPool(corePoolSize, r -> {
Thread t = new Thread(r);
t.setName("VideoTask-" + t.getId());
return t;
});
// 分割视频任务(提取关键帧加速分割)
videoExecutor.submit(() -> {
List<KeyFrame> keyFrames = extractKeyFrames(inputPath);
splitVideoByKeyFrames(inputPath, outputDir, timePoints, keyFrames);
});
// 特效处理任务(并行计算,实时预览同步)
videoExecutor.submit(() -> {
applyEffects(clipPaths, effectParams);
});
// 合并任务
videoExecutor.submit(() -> {
mergeVideo(clipPaths, outputPath);
});
videoExecutor.shutdown();
5) 【面试口播版答案】
在万兴视频编辑APP的视频剪辑功能中,我负责多线程处理开发。视频剪辑流程包括:先用FFmpeg解析视频文件,提取关键帧(关键帧能减少分割时的帧处理量,加速分割步骤),按用户设定的时间点分割视频为多个片段;接着并行处理特效(如滤镜、转场),同时实现实时预览同步;最后合并片段输出。为了提升性能,我设计了一个线程池,核心线程数等于设备CPU核心数(比如8核设备设为8),最大线程数为核心数的两倍(16),任务队列用无界队列缓冲任务。资源竞争方面,视频文件访问用按视频路径加锁(细粒度锁,避免整个视频文件加锁导致卡顿),特效参数共享用ConcurrentHashMap。线程安全通过ReentrantLock控制文件操作,AtomicInteger更新特效参数。遇到线程死锁时,按顺序加锁(先视频锁再特效锁)解决;资源竞争导致的卡顿,通过按功能模块分锁(分割、特效、合并各用独立锁)优化。最终测试显示,10GB视频剪辑速度提升约40%,卡顿率从2%降至0.1%。
6) 【追问清单】
7) 【常见坑/雷区】