首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >单个ScheduledExecutorService实例与多个ScheduledExecutorService实例

单个ScheduledExecutorService实例与多个ScheduledExecutorService实例
EN

Stack Overflow用户
提问于 2022-03-06 16:10:47
回答 1查看 336关注 0票数 0

我有一个服务,它使用ScheduledExecutorService为用户调度异步任务。每个用户将触发该服务来调度两个任务。(第一任务调度具有固定延迟(例如10秒间隔)的第二个任务)伪码代码说明:

代码语言:javascript
复制
task1Future = threadPoolTaskScheduler.schedule(task1);
for(int i = 0; i< 10000; ++i) {
    task2Future = threadPoolTaskScheduler.schedule(task2);
    task2Future.get(); // Takes long time
    Thread.sleep(10);
}

task1.Future.get();

假设我有10000用户同时使用该服务,我们可以为我的服务配置两种ScheduledExecutorService:

  1. 为所有用户提供一个ScheduledExecutorService。
  2. 为每个用户创建一个ScheduledExecutorService。

我能想到的第一种方法是:

优点:

  1. 易于控制线程池中的线程数。
  2. 避免为计划的任务创建新线程。

缺点:

  1. 始终保持多个线程可用可能会浪费计算机资源。
  2. 可能会因为缺少可用线程而导致服务挂起。(例如,将线程池大小设置为10,然后有一个100人同时使用该服务,然后在输入第一个任务后,它尝试调度第二个任务,然后发现没有可用的线程来调度第二个任务)

关于第二种方法我能想到什么

优点:

  1. 避免在用户数量较少时始终保持多个线程可用。
  2. 总是可以为大量的同时使用提供线程。

缺点:

  1. 创建新线程会产生间接费用。
  2. 不知道如何控制服务的最大线程数。可能会导致内存耗尽空间。

对哪条路更好有什么想法吗?

EN

回答 1

Stack Overflow用户

发布于 2022-03-06 17:16:41

单个ScheduledExecutorService驱动许多任务

ScheduledExecutorService的全部目的是在经过一定时间之后维护要执行的任务集合。

因此,考虑到您描述的场景,您只需要一个ScheduledExecutorService对象。将您的10,000个任务提交到该对象。每个任务大约在其指定延迟过去时执行。简单又简单。

线程池大小

真正的问题是决定给ScheduledExecutorService分配多少个线程。

当前在OpenJDK项目中实现的线程直接映射到宿主OS线程。这使得它们在CPU和内存使用方面相对重量级。换句话说,当前Java线程是“昂贵的”。

计算线程池大小没有简单的简单答案。最优的数量是最小的线程数量,可以跟上工作负载,而不过度负担主机的有限数量的核心和有限的内存。如果搜索堆栈溢出,就会发现许多关于决定在池中使用多少线程的讨论。

工程织机

并密切关注https://wiki.openjdk.java.net/display/loom/Main的进展及其将虚拟线程引入Java的承诺。这种技术有可能从根本上改变决定线程池大小的演算。使用CPU和内存,虚拟线程将更加高效。换句话说,虚拟线程将相当“便宜”,“便宜”。

执行者服务是如何工作的

你说过:

输入第一个任务,然后尝试调度第二个任务,然后发现没有可用的线程来调度第二个任务。

这不是计划执行器服务(SES)的工作方式。

如果当前由SES执行的任务需要自行调度,或者其他一些任务需要稍后执行,则将提交的任务添加到SES内部维护的队列中。没有必要立即有一个线程可用。除了队列添加之外,什么都不会立即发生。稍后,当添加的任务的指定延迟已经过去时,SES将在其线程池中寻找一个可用的线程来执行该任务,该任务在时间上排队了一段时间。

您似乎需要在特定线程上管理每个任务的执行时间。但这是预定执行者服务的工作。SES跟踪提交执行的任务,注意它们指定的延迟何时过去,并从托管线程池中在线程上调度它们的执行。你不需要处理任何事情。唯一的挑战是为池分配适当数量的线程。

多执行者服务

你评论说:

为什么不使用多个ScheduledExecutorService实例

因为在你的场景中,没有好处。你的问题意味着你有许多相似的任务,但没有优先排序。在这种情况下,只需使用一个执行者服务。一个有12个线程的预定执行器服务将得到与3个服务相同的工作量,每个服务有4个线程。

至于多余的线程,它们不是负担。任何没有要执行的任务的线程几乎不需要使用CPU时间。池可能会也可能不会在一段时间后关闭一些未使用的线程。但是这样的策略取决于执行器服务的线程池的实现,并且对我们作为调用程序员是透明的。

如果场景不同,其中一些任务会阻塞很长时间,或者需要对某些任务进行优先级排序,那么您可能希望将这些任务隔离到单独的executor服务中。

在今天的Java中(在使用虚拟线程的Project之前),当线程块中的代码出现时,该线程只会等待解除阻塞。阻塞意味着您的代码正在执行等待响应的操作。例如,对套接字或web服务块进行网络调用、写入存储块和访问外部数据库块。理想情况下,您不会编写阻塞很长时间的代码。但有时候你必须。

在某些任务运行时间很长的情况下,或者相反,有些任务必须优先执行才能快速执行,那么是的,使用多个executor服务。

例如,假设您有一台16核计算机,除了您的Java应用程序之外,没有什么其他的运行。对于长期运行的任务,您可能有一个最大线程池大小为4的executor服务;对于多个运行的任务,您可能有一个线程池的最大大小为7的执行器服务;对于很少运行但必须快速运行的任务,可能有一个线程池最大大小为2的执行程序服务。(这里的数字是任意的例子,而不是建议。)

其他方法

作为评论,还有其他管理并发的框架。这里讨论的ScheduledExecutorService是通用的。

例如,秋千JavaFX春天雅加达EE都有各自的并发管理。考虑使用那些对你的特定项目感兴趣的项目。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71371997

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档