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

发布时间:2026/7/17 12:28:02
多线程下任务状态异常的问题解决 多线程下任务状态异常的问题解决场景描述问题描述问题分析相关知识总结事务范围循环中的更新锁和并发超时和异常处理问题解决场景描述在一个线程中将一批任务通过循环依次添加到LinkedBlockingQueue中并将任务状态改为待执行。后台使用mysql数据库。然后另外有一个线程从这个queue中阻塞取出任务并执行这时将任务状态修改为执行中。TransactionalpublicvoidtaskBatchSchedule(ListIntegerids){for(Integerid:ids){TasktaskgetTask(id);queue.put(task);updateTaskWait(task);}}问题描述在这个场景下任务状态的变更有时候正常有时出现问题第一个任务状态一直已经执行但状态还为待执行执行结束后任务状态修改为执行结束。接着第二个任务正常显示任务状态。问题分析这里有生产和消费两个线程当生产线程循环去添加任务并连接数据库更新任务状态。当生产端还没结束事务还未提交一个方法视为一个事务。此时消费端已经取出任务队列中第一个任务去执行。当它去更改任务状态时由于生产线程的事务还未提交。消费线程等待超时后便继续向后执行任务状态修改失败。在我这个场景中第一个任务执行的时候最容易出现该问题因为此时生产和消费线程同时竞争数据库资源第二或者后面的任务在执行的时候生产线程已经结束就不太会出现这个问题。相关知识总结事务范围当方法上标注了Transactional注解时整个方法体内的所有数据库操作都会在一个统一的事务范围内进行。这意味着事务会在方法执行开始时开启并在方法正常完成时提交或者在方法中抛出未被捕获的异常时回滚。循环中的更新如果在一个循环中更新多条记录这些更新操作都会在同一事务中进行。即使循环中有多个数据库操作也只有在循环结束后整个方法执行完成时事务才会提交。锁和并发在循环中更新数据时如果其他线程尝试同时更新相同的记录那么这些线程将等待锁释放或者因为锁等待超时而失败。MySQL默认使用行级锁在InnoDB存储引擎中当一个事务正在更新一行数据时它会对那行数据加上排他锁X锁阻止其他事务同时更新该行数据。超时和异常处理通过Transactional(timeout seconds)来设置事务的最大执行时间。如果事务在此时间内没有完成Spring会自动回滚事务并抛出异常。如果事务因为长时间等待锁而超时MySQL会抛出LockWaitTimeoutExceptionSpring会将其转换为TransactionSystemException异常。捕获并处理TransactionSystemException异常以确保应用程序能够优雅地处理这种情形。调整MySQL的innodb_lock_wait_timeout系统变量来配置数据库级别的锁等待超时时间。问题解决问题在于两个线程资源争夺所造成所以这里我使用了ReentrantLock来同步生产和消费线程。另外将生产线程里循环更新任务状态改为批量更新特别是在数据批次较大的时候能够显著减少数据库操作次数减少事务持续时间。愿你我都能在各自的领域里不断成长勇敢追求梦想同时也保持对世界的好奇与善意。