当前位置: 首页 > news >正文

巧用newSingleThreadExecutor让异步任务顺序跑

背景

Flume 是 Cloudera 提供的一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统 。一个用来控制 Flume 采集任务的 Web 应用,需要对任务进行管理,主要操作「启动、停止、新建、编辑、删除」,本质就是对 Flume 进程进行管理。

任务控制流程:

  1. 任务启动:创建一个 Flume 进程。
  2. 任务停止:停止该 Flume 进程。
  3. 修改启动状态的任务:先停止正在执行的 Flume 进程、再创建一个 Flume 进程。
  4. 任务删除:启动状态的任务先停止 Flume 进程、再删除任务信息。

本文介绍近期对这个功能的优化操作:用 Executors.newSingleThreadExecutor() 单线程调度对任务的处理命令,保证异步任务能按页面提交的顺序顺次执行

不间断地 在 CSDN 写博客十多年了,CSDN 有流量没收益,转场掘金,有收益,没流量。本文首发掘金, 《掘金金石计划投稿》求赞!

旧逻辑

任务管理类是个单例,用了 ThreadPoolExecutor 线程池去调度 Flume 进程的操作。但是线程池没法保证任务的执行顺序,所以加了很多 awaitsleep 操作,等待任务执行完成后才返回响应结果给页面。

这个思路没问题,必要的等待可以保证后台的 Flume 进程按页面的操作指令执行,但用户体验很纠结。

异步任务管理过程中等待常量是 2秒,加上整个 Web 处理操作,以及 Controller 里面的 Sleep 操作,通过 Web 页面对 Flume 任务的管理操作响应时间平均 8 秒左右。

我在测试的时候编辑一个启用状态的任务,提交后需要心里默数到 20 才能看到页面操作结果,确实需要很大的耐心。现场也反馈过这个问题,怎么优化呢?

优化思路

既然都用异步了,为什么非要 awaitsleep 呢?最初思路是,直接去掉这些代码,页面响应果然很快,但是操作结果总是不合理。

  1. 停止、启动连续操作时,Flume 进程并没有启动:点击 「停止」操作,立即点「启动」,Flume 进程并没有起来。
  2. 编辑启动状态的任务:先停止、再启动操作,进程也没有启动。

这是因为线程池调度任务的是多线程的,而停止操作为了保证进程能被 kill 掉,它的逻辑是:

kill 进程ID
休眠 2 秒
再 kill -9

启动操作命令和停止操作一起的时候,最终启动的进程 2秒后又被 kill 掉了,所以直接去掉休眠操作不行。除了休眠等待,怎么保证线程池提按 Runnable 的提交顺序执行呢?

解决办法

更换线程池类型,用 Executors.newSingleThreadExecutor() 保证按提交顺序执行 Runnable;前端只管提交操作命令,后台调度时去掉所有的 await /sleep 等阻塞操作,立即返回响应结果给页面。

优化前,修改一个启动状态的任务,耗时 11 秒:
在这里插入图片描述
优化后,相同操作耗时 700 毫秒:
在这里插入图片描述

启示录

除了休眠等待,怎么保证线程池提按 Runnable 的提交顺序执行呢?我甚至尝试了去更改 flume-ng 脚本,启动任务之前先 kill 掉之前的任务,结果直接把刚刚启动的 flume 任务又给 kill 掉了。

后来想到了还是要在线程池的调度顺序上,如何让Java的线程池顺序执行任务?这不就是 newSingleThreadExecutor 嘛?

他强任他强,清风拂山冈;任他前端怎么点,单线程调度按序走!
不搭题,就是想到了这句话而已。

不间断地 在 CSDN 写博客十多年了,CSDN 有流量没收益,转场掘金,有收益,没流量。本文首发掘金, 《掘金金石计划投稿》求赞!

相关文章:

  • 构建一个强大的小型虚拟负载
  • 记录SpringBoot启动报错解决
  • Spring IoC【控制反转】DI【依赖注入】
  • 爬虫逆向实战(41)-某花顺登陆(Cookie、MD5、SHA256)
  • 关于scrapy模块中间件的简单理解
  • 案例分享:高科技企业产品管理部门设置和产品经理岗位设置
  • MySQL 面试突击指南:核心知识点解析1
  • YOLOv10改进 | 注意力篇 | YOLOv10引入YOLO-Face提出的SEAM注意力机制优化物体遮挡检测
  • 改进YOLOv7 | 在 ELAN 模块中添加【Triplet】【SpatialGroupEnhance】【NAM】【S2】注意力机制 | 附详细结构图
  • 浏览器组成的介绍
  • QT中QSettings的使用系列之二:保存和恢复应用程序主窗口
  • bash: nvcc: command not found
  • 查看 MAC 的 shell 配置文件
  • 2024考古之还在用原始JDBC开发 手搓 案例 实现一个模块的增删改
  • 基于51单片机的篮球计分器设计
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • .pyc 想到的一些问题
  • 07.Android之多媒体问题
  • Cumulo 的 ClojureScript 模块已经成型
  • es6要点
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • Linux各目录及每个目录的详细介绍
  • Linux快速配置 VIM 实现语法高亮 补全 缩进等功能
  • maya建模与骨骼动画快速实现人工鱼
  • Node 版本管理
  • Octave 入门
  • Sass 快速入门教程
  • SSH 免密登录
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • vue-router的history模式发布配置
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 半理解系列--Promise的进化史
  • 给github项目添加CI badge
  • 前嗅ForeSpider采集配置界面介绍
  • 深度学习入门:10门免费线上课程推荐
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 最近的计划
  • C# - 为值类型重定义相等性
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • ‌JavaScript 数据类型转换
  • #DBA杂记1
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • (4)Elastix图像配准:3D图像
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (分享)自己整理的一些简单awk实用语句
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (六)c52学习之旅-独立按键
  • (六)DockerCompose安装与配置
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (限时免费)震惊!流落人间的haproxy宝典被找到了!一切玄妙尽在此处!
  • (一)VirtualBox安装增强功能
  • (转)大型网站架构演变和知识体系
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .net core 控制台应用程序读取配置文件app.config