news 2026/6/10 12:18:49

多线程执行任务-效率

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
多线程执行任务-效率

说明:最近在开发一个功能,大概是一个区域下有多个电站,而一个电站下又有多个摄像头,一个摄像头上又有几百个预置位(固有的转动位置),需要转动预置位,等待10s,然后获取预置位上的PTZ(坐标值)数据;单线程的话,算了一笔时间账,需要80多个小时;多线程的话,5个就只需要16小时左右,线程池设置更大,则用时更少,就可以大幅度的减少时间提高效率。

publicbooleansetPresetPtzTask(){if(!enabled){log.info("未开启获取预置位PTZ的定时任务!");returntrue;}// 重置停止标志this.stopFlag=false;// 记录执行进度(使用原子变量确保线程安全)inttotalStations=0;AtomicIntegerexecutedStations=newAtomicInteger(0);inttotalCameras=0;AtomicIntegerexecutedCameras=newAtomicInteger(0);inttotalPresets=0;AtomicIntegerexecutedPresets=newAtomicInteger(0);try{// 查询符合条件的预置位List<CameraPresetVo>presets=baseMapper.getEffectivePresets();if(CollectionUtil.isEmpty(presets)){log.info("没有PTZ值为零的预置位数据!");returntrue;}// 按电站分组Map<String,List<CameraPresetVo>>stationPresetMap=presets.stream().collect(Collectors.groupingBy(CameraPresetVo::getOrgId));totalStations=stationPresetMap.size();// 计算总摄像头数和总预置位数for(List<CameraPresetVo>stationPresetList:stationPresetMap.values()){Map<String,List<CameraPresetVo>>cameraMap=stationPresetList.stream().collect(Collectors.groupingBy(CameraPresetVo::getCameraId));totalCameras+=cameraMap.size();// 计算每个电站的预置位数for(List<CameraPresetVo>cameraPresetList:cameraMap.values()){totalPresets+=cameraPresetList.size();}}log.info("任务开始执行,总共 {} 个电站,{} 个摄像头,{} 个预置位",totalStations,totalCameras,totalPresets);// 创建线程池// int corePoolSize = Runtime.getRuntime().availableProcessors();ExecutorServiceexecutorService=Executors.newFixedThreadPool(corePoolSize);List<Future<?>>futures=newArrayList<>();// 遍历每个电站for(Map.Entry<String,List<CameraPresetVo>>stationEntry:stationPresetMap.entrySet()){// 检查是否需要停止if(stopFlag){log.info("任务停止执行,收到停止指令");log.info("执行进度: 总共 {} 个电站,已执行 {} 个电站;总共 {} 个摄像头,已执行 {} 个摄像头;总共 {} 个预置位,已执行 {} 个预置位",totalStations,executedStations.get(),totalCameras,executedCameras.get(),totalPresets,executedPresets.get());executorService.shutdownNow();returnfalse;}StringstationId=stationEntry.getKey();List<CameraPresetVo>stationPresets=stationEntry.getValue();log.info("开始处理电站: {} ({} / {})",stationId,executedStations.get()+1,totalStations);// 按摄像头ID分组Map<String,List<CameraPresetVo>>cameraPresetMap=stationPresets.stream().collect(Collectors.groupingBy(CameraPresetVo::getCameraId));// 为每个摄像头创建任务for(Map.Entry<String,List<CameraPresetVo>>cameraEntry:cameraPresetMap.entrySet()){StringcameraId=cameraEntry.getKey();//根据预置位序号升序List<CameraPresetVo>cameraPresets=cameraEntry.getValue().stream().sorted(Comparator.comparing(CameraPresetVo::getPresetIndex)).collect(Collectors.toList());finalStringcurrentCameraId=cameraId;finalList<CameraPresetVo>currentPresets=cameraPresets;finalintcameraIndex=executedCameras.get()+1;// 提交摄像头处理任务intfinalTotalCameras=totalCameras;Future<?>future=executorService.submit(()->{log.info("开始处理摄像头: {} ({} / {})",currentCameraId,cameraIndex,finalTotalCameras);try{// 遍历每个预置位for(CameraPresetVopreset:currentPresets){// 检查是否需要停止if(stopFlag){log.info("摄像头 {} 任务停止执行,收到停止指令",currentCameraId);return;}try{// 转动到预置位CameraActionRequestDtorequestDto=newCameraActionRequestDto();requestDto.setId(currentCameraId);requestDto.setPresetIndex(preset.getPresetIndex());requestDto.setThirdApp(false);//无锁,直接调用转动预置位booleangotoResult=gotoPresetImpl(requestDto);if(!gotoResult){log.error("转动预置位失败,摄像头: {},id: {}, 预置位: {}",preset.getDevName(),currentCameraId,preset.getPresetIndex());// 更新未获取成功预置的位状态this.updatePreset(currentCameraId,preset);continue;}// 等待10秒TimeUnit.SECONDS.sleep(10);// 检查是否需要停止if(stopFlag){log.info("摄像头 {} 任务停止执行,收到停止指令",currentCameraId);return;}// 获取PTZ值PtzVoptzVo=getPtz(currentCameraId);if(ptzVo==null){log.error("获取PTZ值失败,摄像头: {},id: {}",preset.getDevName(),currentCameraId);this.updatePreset(currentCameraId,preset);continue;}// 保存PTZ值,更新状态值this.savePreset(currentCameraId,preset,ptzVo);// 预置位处理完成executedPresets.incrementAndGet();}catch(Exceptione){log.error("处理预置位失败,摄像头: {},id: {} 预置位: {}, 错误: {}",preset.getDevName(),currentCameraId,preset.getPresetIndex(),e.getMessage());// 继续处理下一个预置位}}// 摄像头处理完成intcompletedCameraCount=executedCameras.incrementAndGet();log.info("摄像头处理完成,已执行 {} / {} 个摄像头",completedCameraCount,finalTotalCameras);}catch(Exceptione){log.error("处理摄像头 {} 失败,错误: {}",currentCameraId,e.getMessage());}});futures.add(future);}// 等待当前电站的所有摄像头任务完成for(Future<?>future:futures){try{future.get();}catch(Exceptione){log.error("等待摄像头任务完成失败,错误: {}",e.getMessage());}}futures.clear();// 电站处理完成intcompletedStationCount=executedStations.incrementAndGet();log.info("电站处理完成,已执行 {} / {} 个电站",completedStationCount,totalStations);}// 关闭线程池executorService.shutdown();try{if(!executorService.awaitTermination(60,TimeUnit.SECONDS)){executorService.shutdownNow();}}catch(InterruptedExceptione){executorService.shutdownNow();Thread.currentThread().interrupt();}// 统一输出最终执行结果log.info("任务执行完成,执行结果如下:");log.info("总共 {} 个电站,已执行 {} 个电站",totalStations,executedStations.get());log.info("总共 {} 个摄像头,已执行 {} 个摄像头",totalCameras,executedCameras.get());log.info("总共 {} 个预置位,已执行 {} 个预置位",totalPresets,executedPresets.get());returntrue;}catch(Exceptione){log.error("任务执行失败,错误: {}",e.getMessage());// 统一输出执行进度log.info("执行进度如下:");log.info("总共 {} 个电站,已执行 {} 个电站",totalStations,executedStations.get());log.info("总共 {} 个摄像头,已执行 {} 个摄像头",totalCameras,executedCameras.get());log.info("总共 {} 个预置位,已执行 {} 个预置位",totalPresets,executedPresets.get());returnfalse;}}

停止任务:

publicvoidstopSetPresetPtz(){this.stopFlag=true;log.info("手动停止 setPresetPtz() 任务");}

全局变量:

// 停止标志,用于手动停止任务执行privatevolatilebooleanstopFlag=false;

Volatile 是 Java 中一个非常有用的关键字,用于保证多线程环境下共享变量的可见性和一致性。
可见性:Volatile 可以保证所有线程都能看到共享变量的最新值。当一个线程修改了共享变量的值时,JVM 会将该值刷新到主内存中。其他线程读取共享变量的值时,会从主内存中读取最新的值。
一致性:Volatile 可以保证共享变量的写操作对所有线程都具有原子性。这意味着对共享变量的写操作要么全部成功,要么全部失败,不会出现部分成功的情况。
实现原理
内存屏障: Volatile 会在指令序列中插入内存屏障,禁止处理器对指令进行重排序。
缓存一致性协议: Volatile 会使用缓存一致性协议来保证所有线程都能看到共享变量的最新值。

多线程的使用逻辑
1.创建线程池,设置默认大小,或者根据运行容器获取的数量调节;
2.线程池提交任务,然后添加到Futrue进行任务管理;
3.循环等待,等待结果获取;
4.清理管理器Future;
5.关闭线程池;
6.等待未完成任务结束,异常则中断线程;

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 7:16:17

STM32定时器与PWM的进阶应用:打造智能灯光系统

STM32定时器与PWM的智能灯光系统实战指南 1. 智能灯光系统的核心组件 在嵌入式开发领域&#xff0c;STM32的定时器和PWM功能为构建智能灯光系统提供了强大支持。不同于简单的流水灯或呼吸灯实验&#xff0c;真正的智能灯光系统需要考虑以下几个关键要素&#xff1a; 多通道控…

作者头像 李华
网站建设 2026/6/1 17:58:58

Qwen3-ASR-0.6B语音识别:5分钟搭建本地智能转写工具

Qwen3-ASR-0.6B语音识别&#xff1a;5分钟搭建本地智能转写工具 1. 引言&#xff1a;为什么你需要一个真正“属于你”的语音转写工具 你有没有过这样的经历&#xff1a;会议录音存了一堆&#xff0c;却没时间听&#xff1b;采访素材长达两小时&#xff0c;手动整理要一整天&a…

作者头像 李华
网站建设 2026/6/5 12:32:55

BGE-M3部署实操:WSL2环境Windows本地部署BGE-M3嵌入服务全记录

BGE-M3部署实操&#xff1a;WSL2环境Windows本地部署BGE-M3嵌入服务全记录 1. 为什么选BGE-M3&#xff1f;它到底能做什么 你可能已经用过不少文本向量化工具&#xff0c;但BGE-M3有点不一样——它不是“又一个”嵌入模型&#xff0c;而是目前少有的、真正把语义理解、关键词…

作者头像 李华
网站建设 2026/6/5 20:27:04

JVM堆内存溢出问题在Elasticsearch中的排查

Elasticsearch JVM堆溢出排查实战:从内存模型误读到根因精准打击 你有没有遇到过这样的深夜告警? 凌晨两点,Kibana监控面板突然炸开一片红色:某数据节点 jvm.mem.heap_used_percent 突破98%, thread_pool.search.queue 积压飙升至2万+,紧接着是连续的 503 Service …

作者头像 李华
网站建设 2026/6/9 0:14:02

QWEN-AUDIO保姆级教程:从安装到生成第一段语音

QWEN-AUDIO保姆级教程&#xff1a;从安装到生成第一段语音 1. 这不是“又一个TTS工具”&#xff0c;而是会呼吸的语音合成系统 你有没有试过用语音合成工具读一段文字&#xff0c;结果听着像机器人在念说明书&#xff1f;语调平直、节奏僵硬、情感缺失——那种“技术上没错&a…

作者头像 李华