news 2026/3/8 2:20:45

多线程执行任务-效率

作者头像

张小明

前端开发工程师

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/3/4 19:02:48

Swin2SR完整流程:从上传到保存的每一步说明

Swin2SR完整流程&#xff1a;从上传到保存的每一步说明 1. 什么是Swin2SR&#xff1f;——你的AI显微镜来了 你有没有遇到过这样的情况&#xff1a;一张特别喜欢的AI生成图&#xff0c;只有512512&#xff0c;放大后全是马赛克&#xff1b;一张老照片发黄模糊&#xff0c;想打…

作者头像 李华
网站建设 2026/3/5 19:03:06

从0开始学文本向量化:Qwen3-Embedding-0.6B新手指南

从0开始学文本向量化&#xff1a;Qwen3-Embedding-0.6B新手指南 你是否遇到过这样的问题&#xff1a;想用AI做语义搜索&#xff0c;却卡在“怎么把一句话变成数字”这一步&#xff1f;想搭建本地知识库&#xff0c;却被各种embedding模型的参数、设备要求、调用方式绕晕&#…

作者头像 李华
网站建设 2026/3/5 17:29:00

Qwen2.5-Coder-1.5B快速入门:一键部署与代码生成

Qwen2.5-Coder-1.5B快速入门&#xff1a;一键部署与代码生成 你是否曾为写一段正则表达式反复调试半小时&#xff1f;是否在接手陌生项目时&#xff0c;对着几百行嵌套逻辑发呆&#xff1f;是否想快速生成一个带单元测试的Python工具脚本&#xff0c;却卡在环境配置上&#xf…

作者头像 李华
网站建设 2026/3/4 12:09:55

Qwen-Image-2512-SDNQ WebUI实战案例:用‘春节喜庆场景’生成系列节日海报

Qwen-Image-2512-SDNQ WebUI实战案例&#xff1a;用‘春节喜庆场景’生成系列节日海报 1. 为什么选这个模型做春节海报&#xff1f;真实效果说话 春节临近&#xff0c;电商运营、社区宣传、新媒体编辑都在赶制节日素材。你是不是也经历过&#xff1a;找设计师排期要等三天&am…

作者头像 李华
网站建设 2026/3/5 10:25:45

YOLOE官版镜像推理速度快1.4倍?实测结果来了

YOLOE官版镜像推理速度快1.4倍&#xff1f;实测结果来了 你有没有遇到过这样的情况&#xff1a;模型结构明明很轻量&#xff0c;参数量比YOLOv8还少&#xff0c;但一跑推理就卡在GPU显存加载上&#xff0c;预热时间长、首帧延迟高、批量处理吞吐上不去&#xff1f;更别提在开放…

作者头像 李华
网站建设 2026/3/5 7:25:13

企业级AI应用实战:Qwen3-VL多模态助手飞书集成

企业级AI应用实战&#xff1a;Qwen3-VL多模态助手飞书集成 你是否经历过这样的场景&#xff1f;市场部同事凌晨三点发来一张活动海报截图&#xff0c;问&#xff1a;“这个配色会不会太刺眼&#xff1f;”&#xff1b;客服团队每天要人工核对上百张用户上传的故障设备照片&…

作者头像 李华