Java 计划作业任务

Java 计划作业任务,java,mysql,multithreading,scheduled-tasks,job-scheduling,Java,Mysql,Multithreading,Scheduled Tasks,Job Scheduling,主题: 我正在尝试用Java实现一个基本的作业调度,以处理个人学习项目的重复性持久化调度任务。我不想使用任何现成的库,比如Quartz/Obsidian/Cron4J/等等 目标: 作业必须是持久性的,才能处理服务器关闭 作业执行时间最多可达2-5 mn。 管理大量的工作 多线程 轻快; 我所有的工作都在MySQL数据库中 JOB_TABLE (id, name, nextExecution,lastExecution, status(IDLE,PENDING,RUNNING)) 逐步: 从“

主题:


我正在尝试用Java实现一个基本的作业调度,以处理个人学习项目的重复性持久化调度任务。我不想使用任何现成的库,比如Quartz/Obsidian/Cron4J/等等

目标:

作业必须是持久性的,才能处理服务器关闭 作业执行时间最多可达2-5 mn。 管理大量的工作 多线程 轻快; 我所有的工作都在MySQL数据库中

JOB_TABLE (id, name, nextExecution,lastExecution, status(IDLE,PENDING,RUNNING))
逐步:

从“job_TABLE”中检索每个作业,其中“nextExecution>now”和“status=IDLE”。此步骤由单个线程每10mn执行一次

对于检索到的每个作业,我在ThreadPoolExecutor中放入一个新线程,然后在“作业表”中将作业状态更新为“挂起”

当作业线程正在运行时,我将作业状态更新为“正在运行”

作业完成后,我用当前时间更新lastExecution,设置新的nextExecution时间,并将作业状态更改为“IDLE”

当服务器启动时,我将每个挂起/正在运行的作业放在ThreadPoolExecutor中

问题/意见:

步骤2:ThreadPoolExecutor是否会处理大量线程~20000? 我应该使用NoSQL解决方案而不是MySQL吗? 这是处理此类用例的最佳解决方案吗?
这是一个草稿,没有任何代码。我愿意接受建议、评论和批评!

您可以使用ThreadPoolExecutorsetMaximumPoolSizeint声明最大池大小。由于Integer.MAX大于20000,技术上可以

另一个问题是,您的机器是否支持这么多线程运行。您将提供足够的RAM,以便每个线程在堆栈上进行分配

在现代台式机或笔记本电脑上使用电子不应该是个问题,但在移动设备上,这可能是个问题

从文件:

核心和最大池大小

ThreadPoolExecutor将自动 根据边界集调整池大小,请参见getPoolSize 按corePoolSize查看getCorePoolSize和maximumPoolSize查看 getMaximumPoolSize。在方法中提交新任务时 executejava.lang.Runnable和少于corePoolSize的线程 运行时,将创建一个新线程来处理该请求,即使其他线程 工作线程处于空闲状态。如果超过corePoolSize但小于 除了运行maximumPoolSize线程外,还将创建一个新线程 仅当队列已满时。通过设置corePoolSize和maximumPoolSize 同样,您可以创建一个固定大小的线程池 将maximumPoolSize设置为基本无界值,例如 Integer.MAX_值,则允许池容纳任意 并发任务数。最典型的是核心和最大池 尺寸仅在施工时设置,但也可以更改 动态使用setCorePoolSizeint和setMaximumPoolSizeint


关于数据库。创建一个不依赖于数据库结构的解决方案。然后你可以设置两个环境并对其进行测量。从你知道的技术开始。但要对其他解决方案保持开放。一开始,关系数据库应该与性能保持同步。如果你管理得当,以后就不应该成为问题。NoSQL正在使用d使用真正的大数据。但对您来说,最好的方法是创建这两个项目并运行一些性能测试。

我在实际项目中完成了与您类似的任务,但都是在.NET中完成的。以下是关于您的问题,我可以回忆起的内容:

步骤2:ThreadPoolExecutor是否会处理大量线程~20000

我们发现.NET的内置线程池是最糟糕的方法,因为该项目是一个web应用程序。原因:web应用程序依赖于内置线程池,该线程池是静态的,因此在运行过程中为所有用途共享,以在单独的线程中运行每个请求,同时保持线程的有效循环我们内部处理的ame线程池将耗尽它,并且不会为用户请求留下任何空闲线程,或者破坏它们的性能,这是不可接受的

由于你似乎在运行大量的作业,20k对于一台机器来说是一个很大的工作量,那么你肯定应该寻找一个自定义线程池。虽然没有必要编写自己的线程池,但我打赌有现成的解决方案,而且编写一个线程池远远超出了你的学习项目所需的范围。如果我理解正确,请参阅评论大学项目

我应该使用NoSQL解决方案而不是MySQL吗

视情况而定。显然,您需要同时更新作业状态,因此,您可以从多个线程同时访问一个表。如果您做得正确,数据库可以很好地扩展到这一点。以下是我所指的正确操作:

设计代码时,每个作业只影响数据库中自己的行子集,这包括其他表。如果能够做到这一点,则不需要以tra形式在数据库级别上使用任何显式锁 nsaction序列化级别。您甚至可以强制执行一个自由的序列化级别,允许脏读或幻像读,这将执行得更快。但要小心,您必须小心确保没有作业会在同一行上同时出现。这在现实项目中很难实现,因此您可能应该在db锁定中寻找替代方法

使用适当的事务序列化模式。事务序列化模式定义数据库级别的锁定行为。您可以将其设置为锁定整个表,只锁定您影响的行,或者什么都不锁定。明智地使用它,因为任何误用都可能影响整个应用程序或数据库服务器的数据一致性、完整性和稳定性

我不熟悉NoSQL数据库,所以我只能建议您研究并发功能,并将它们映射到您的场景中。你可以最终找到一个真正合适的解决方案,但你必须根据自己的需要进行检查。根据您的描述,您将必须支持对同一类型对象的同时数据操作,这是表的模拟

这是处理此类用例的最佳解决方案吗

是和否

是的,因为您将遇到开发人员在现实世界中面临的困难任务之一。我和同事的工作经验是我的三倍多,他们比我更不愿意做多线程任务,他们真的很讨厌。如果你觉得这个领域对你来说很有趣,那就玩玩它,尽可能多地学习和提高

不,因为如果你在做一个真实的项目,你需要一些可靠的东西。如果您有这么多问题,您显然需要时间来成熟,并能够为此类任务生成稳定的解决方案。多线程是一个困难的主题,原因有很多:

很难调试 它引入了许多故障点,您需要了解所有这些故障点 除非您坚持公认的规则,否则其他开发人员协助或使用您的代码可能会感到痛苦。 错误处理可能很棘手 行为是不可预测的/不确定的。 现有的解决方案具有高度的成熟度和可靠性,是实际项目的首选方法。缺点是,您必须学习它们,并检查它们是如何根据您的需要定制的

无论如何,如果你需要按照自己的方式来做,然后将你的成果移植到一个真正的项目,或者你自己的项目中,我可以建议你以一种可插入的方式来做这件事。使用抽象、接口编程和其他实践将您自己的特定实现与设置计划作业的逻辑分离。这样,如果这成为一个问题,您可以根据现有的解决方案调整api

最后,但并非最不重要的一点是,我没有看到任何错误处理预测站在你这边。思考和研究工作失败后该怎么办。至少添加一个“失败”状态或在这种情况下保持的内容。当涉及到线程时,错误处理是很棘手的,所以要仔细研究和实践


祝你好运

我不想使用任何现成的库,比如Quartz/Obsidian/Cron4J/等等-为什么不呢?因为这是一个提高我Java知识的研究项目;然后分析这些LIB的代码。那么你就可以学到比重新发明轮子更多的东西。@Vash:我不一定要编写代码,对我来说真正重要的是理解处理这种情况的方法。这种情况下的问题、体系结构和解决方案从内存的角度来看,线程池队列中的1M作业会有问题吗?-关于数据库抽象,您是对的,但根据您的经验,我会处理这种体系结构的一些问题吗?在小型虚拟机上,查看编辑。但底线是,这要视情况而定。关于设计,我也会这么说。这取决于如何调整db。在这一点上,你应该从你的想法开始。然后测量它并尝试在%范围内改进。项目的主要愿景是在有效的时刻执行任务,如何完成只是技术细节。学习一些关于线程管理的课程,然后开始创建一个原型。