news 2026/7/17 12:27:57

多线程下任务状态异常的问题解决

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
多线程下任务状态异常的问题解决

多线程下任务状态异常的问题解决

  • 场景描述
  • 问题描述
  • 问题分析
  • 相关知识总结
    • 事务范围
    • 循环中的更新
    • 锁和并发
    • 超时和异常处理
  • 问题解决

场景描述

在一个线程中将一批任务通过循环依次添加到LinkedBlockingQueue中,并将任务状态改为待执行。后台使用mysql数据库。然后另外有一个线程从这个queue中阻塞取出任务,并执行,这时将任务状态修改为执行中。

@TransactionalpublicvoidtaskBatchSchedule(List<Integer>ids){for(Integerid:ids){Tasktask=getTask(id);queue.put(task);updateTaskWait(task);}}

问题描述

在这个场景下,任务状态的变更有时候正常,有时出现问题:第一个任务状态一直已经执行但状态还为待执行,执行结束后任务状态修改为执行结束。接着第二个任务正常显示任务状态。

问题分析

这里有生产和消费两个线程,当生产线程循环去添加任务并连接数据库更新任务状态。当生产端还没结束,事务还未提交(一个方法视为一个事务)。此时,消费端已经取出任务队列中第一个任务去执行。当它去更改任务状态时,由于生产线程的事务还未提交。消费线程等待超时后便继续向后执行,任务状态修改失败。

在我这个场景中,第一个任务执行的时候最容易出现该问题,因为此时生产和消费线程同时竞争数据库资源,第二,或者后面的任务在执行的时候,生产线程已经结束,就不太会出现这个问题。

相关知识总结

事务范围

  • 当方法上标注了@Transactional注解时,整个方法体内的所有数据库操作都会在一个统一的事务范围内进行。
  • 这意味着事务会在方法执行开始时开启,并在方法正常完成时提交,或者在方法中抛出未被捕获的异常时回滚。

循环中的更新

  • 如果在一个循环中更新多条记录,这些更新操作都会在同一事务中进行。
  • 即使循环中有多个数据库操作,也只有在循环结束后整个方法执行完成时,事务才会提交。

锁和并发

  • 在循环中更新数据时,如果其他线程尝试同时更新相同的记录,那么这些线程将等待锁释放,或者因为锁等待超时而失败。
  • MySQL默认使用行级锁,在InnoDB存储引擎中,当一个事务正在更新一行数据时,它会对那行数据加上排他锁(X锁),阻止其他事务同时更新该行数据。

超时和异常处理

  • 通过@Transactional(timeout = seconds)来设置事务的最大执行时间。如果事务在此时间内没有完成,Spring会自动回滚事务并抛出异常。
  • 如果事务因为长时间等待锁而超时,MySQL会抛出LockWaitTimeoutException,Spring会将其转换为TransactionSystemException异常。捕获并处理TransactionSystemException异常,以确保应用程序能够优雅地处理这种情形。调整MySQL的innodb_lock_wait_timeout系统变量来配置数据库级别的锁等待超时时间。

问题解决

问题在于两个线程资源争夺所造成,所以这里我使用了ReentrantLock来同步生产和消费线程。另外,将生产线程里,循环更新任务状态改为批量更新,特别是在数据批次较大的时候,能够显著减少数据库操作次数,减少事务持续时间。

愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意。

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

DiscordX音乐机器人开发:LavaPlayer与YTDL插件的终极集成指南

DiscordX音乐机器人开发&#xff1a;LavaPlayer与YTDL插件的终极集成指南 【免费下载链接】discordx &#x1f916; Create a discord bot with TypeScript and Decorators! 项目地址: https://gitcode.com/gh_mirrors/di/discordx 想要创建功能强大的Discord音乐机器人…

作者头像 李华
网站建设 2026/7/17 12:26:56

Rust Rosetta Code贡献指南:如何为开源项目提交你的第一个PR

Rust Rosetta Code贡献指南&#xff1a;如何为开源项目提交你的第一个PR 【免费下载链接】rust-rosetta Implementing Rosetta Code problems in Rust. 项目地址: https://gitcode.com/gh_mirrors/ru/rust-rosetta Rust Rosetta Code项目致力于用Rust语言实现Rosetta Co…

作者头像 李华
网站建设 2026/7/17 12:25:56

解密多智能体金融交易框架:如何用AI打造你的专属投资团队

解密多智能体金融交易框架&#xff1a;如何用AI打造你的专属投资团队 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN 你是否曾经想过&#xff0c…

作者头像 李华
网站建设 2026/7/17 12:22:27

STM32N6570外部Flash烧录与FSBL引导配置指南

1. STM32N6570-DK外部Flash烧录与FSBL引导概述STM32N6570-DK开发板搭载了高性能的STM32N6系列微控制器&#xff0c;其独特之处在于支持通过外部Flash存储应用程序并由FSBL&#xff08;First Stage Bootloader&#xff09;进行引导启动。这种架构设计在工业控制、物联网设备等需…

作者头像 李华