ScheduledExecutorService 多线程并行

发布于 2024-11-26 18:05:42 字数 794 浏览 0 评论 0原文

我有兴趣使用 ScheduledExecutorService 为任务生成多个线程(如果之前的任务尚未完成)。例如我需要每0.5秒处理一个文件。第一个任务开始处理文件,0.5 秒后,如果第一个线程未完成,则生成第二个线程并开始处理第二个文件,依此类推。这可以通过以下方式完成:

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(4)
    while (!executor.isShutdown()) {  
        executor.execute(task);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // handle
        }
    }

现在我的问题:为什么我不能使用 executor.scheduleAtFixedRate 来做到这一点?

我得到的是,如果第一个任务需要更长的时间,则第二个任务在第一个任务完成后立即启动,但即使执行器有线程池,也不会启动新线程。 executor.scheduleWithFixedDelay 很清楚 - 它以相同的时间跨度执行任务,并且完成任务需要多长时间并不重要。所以可能我误解了 ScheduledExecutorService 的目的。

也许我应该看看另一种执行者?或者只是使用我在这里发布的代码?有什么想法吗?

I'm interested in using ScheduledExecutorService to spawn multiple threads for tasks if task before did not yet finish. For example I need to process a file every 0.5s. First task starts processing file, after 0.5s if first thread is not finished second thread is spawned and starts processing second file and so on. This can be done with something like this:

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(4)
    while (!executor.isShutdown()) {  
        executor.execute(task);
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // handle
        }
    }

Now my question: Why I can't do it with executor.scheduleAtFixedRate?

What I get is if the first task takes longer, the second task is started as soon as first finished, but no new thread is started even if executor has pool of threads. executor.scheduleWithFixedDelay is clear - it executes tasks with same time span between them and it doesn't matter how long it takes to complete the task. So probably I misunderstood ScheduledExecutorService purpose.

Maybe I should look at another kind of executor? Or just use code which I posted here? Any thoughts?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

淡淡绿茶香 2024-12-03 18:05:42

我通过在每个计划执行中启动一个嵌套的匿名可运行程序解决了这个问题:

final ScheduledExecutorService service = Executors.newScheduledThreadPool(POOL_SIZE);

final Runnable command = new SlowRunnable();

service.scheduleAtFixedRate(
    new Runnable() {
      @Override
      public void run() {
        service.execute(command);
      }
    }, 0, 1, TimeUnit.SECONDS);

在这个示例中,将有 1 个线程在每个时间间隔执行快速指令,因此当下一个时间间隔到期时,它肯定会完成。剩余的 POOL_SIZE-1 线程将并行执行 SlowRunnable 的 run(),这可能需要比单个间隔的持续时间更长的时间。

请注意,虽然我喜欢这个解决方案,因为它最大限度地减少了代码并重用相同的 ScheduledExecutorService,但它的大小必须正确,并且可能无法在每个上下文中使用:如果 SlowRunnable 太慢以至于最多 POOL_SIZE 作业一起执行,那么将会有没有线程能够及时运行计划任务。

另外,如果将间隔设置为 1 TimeUnit.NANOSECONDS,则主可运行对象的执行也可能会变得太慢。

I've solved the problem by launching a nested anonymous runnable in each scheduled execution:

final ScheduledExecutorService service = Executors.newScheduledThreadPool(POOL_SIZE);

final Runnable command = new SlowRunnable();

service.scheduleAtFixedRate(
    new Runnable() {
      @Override
      public void run() {
        service.execute(command);
      }
    }, 0, 1, TimeUnit.SECONDS);

With this example there will be 1 thread executing at every interval a fast instruction, so it will be surely be finished when the next interval is expired. The remaining POOL_SIZE-1 threads will be executing the SlowRunnable's run() in parallel, which may take longer time than the duration of the single interval.

Please note that while I like this solution as it minimize the code and reuse the same ScheduledExecutorService, it must be sized correctly and may not be usable in every context: if the SlowRunnable is so slow that up to POOL_SIZE jobs get executed together, there will be no threads to run the the scheduled task in time.

Also, if you set the interval at 1 TimeUnit.NANOSECONDS it will probably became too slow also the execution of the main runnable.

半枫 2024-12-03 18:05:42

scheduleAtFixedRate 方法就是您要查找的 为了。它会按照给定的时间间隔从池中的线程中启动一个任务,即使之前的任务尚未完成。如果您没有足够的线程来执行处理,请按照 ThreadPoolExecutor 文档

One of the scheduleAtFixedRate methods is what you're looking for. It starts a task in a thread from the pool at the given interval, even if previous tasks haven't finished. If you're running out of threads to do the processing, adjust the pool size constraints as detailed in the ThreadPoolExecutor docs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文