为什么不在当前线程中实现时间控制的任务呢?

发布于 2025-01-10 10:46:03 字数 177 浏览 0 评论 0原文

当实现一个在特定时间范围内处理任务的函数时(例如,每 1 分钟监控一个值,总共 10 分钟时间限制),流行的解决方案是使用 Timer 或 Timer >ScheduledExecutorService java util 类在单独的线程上安排任务。

想知道为什么不在当前线程上实现定时任务而不是创建一个新线程来处理它?

When implementing a function to work on a task in a specific time range (for example, monitor a value every 1 minute and 10 mins time limit in total), the popular solution is to use Timer or ScheduledExecutorService java util classes to schedule tasks on a separate thread.

Wondering why not just implement the timed task on the current thread instead of creating a new thread to handle that?

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

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

发布评论

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

评论(3

妥活 2025-01-17 10:46:03

睡眠主线程会冻结您的应用程序

多线程的全部意义在于从运行应用程序的初始线程中卸载工作。

线程休眠直到某个时间不做任何其他工作。如果您的应用程序的主线程处于睡眠状态,那么您的应用程序将完全挂起且无用。如果运行 GUI 的线程处于睡眠状态,那么您的应用程序对于用户来说似乎已被冻结,显然已崩溃,并且实际上毫无用处。

另外,正如评论的,目前Java中实现的线程在内存和CPU方面相对昂贵。因此,我们通常避免同时运行多个/几个/几十个线程。将来,如果Loom项目成功的话它的虚拟线程,这种情况可能会发生根本性的改变。

您评论道:

我想也许我可以开始时间停止->监视器->返回->睡眠当前线程->监控,当条件满足或超时时退出监控?

这实际上就是 ScheduledExecutorService 确实如此。您将任务定义为RunnableCallable。执行器服务定期运行您的任务。在该任务中,您可以检查您正在等待的条件。

因此,您无需重新发明轮子。使用Java内置的Executors框架;太棒了。

搜索该类名称。关于这个主题已经有很多文章了,其中一些是我撰写的。搜索以了解更多信息。

关于 Timer,这个类几年前就被 Executors 框架取代了。 Javadoc 中记录了这一事实。

任务自行重新安排

您阐明了您的目标是每分钟检查一个条件,最多十次。

实现此目的的一种方法是让任务自行重新安排。

public class ConditionCheckingTask implements Runnable 
{
    private final ScheduledExecutorService ses ;
    private final Instant whenInstantiated = Instant.now() ;

    // Constructor
    public ConditionCheckingTask( final ScheduledExecutorService ses ) {
        this.ses = ses ;
    }

    @Override
    public void run() {
        if( someConditionIsTrue ) {
            doSomething ;
        } else if ( ChronoUnit.MINUTES.between( this.whenInstantiated , Instant.now() ) > 10 ) {
            // We have exceeded our time limit, so let this task die.
            return ;
        } else {  // Else wait a minute to check condition again.
            this.ses.schedule( this , 1 , TimeUnit.MINUTES ) ;
        }
    }
}

确保访问 someConditionIsTrue 是线程安全的。例如,如果其他线程正在翻转布尔标志来指示我们的任务,请将该标志设为 AtomicBoolean。要了解更多信息,请搜索 Stack Overflow,并阅读下面列出的书籍。

在应用程序的某个位置,实例化并记住一个 ScheduledExecutorService 对象。

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor() ;

请务必在应用程序退出之前最终关闭执行程序服务。搜索以了解更多信息。 Stack Overflow 上已多次解决这个问题。

实例化您的任务。将计划的执行程序服务传递给任务的构造函数,以便它可以每分钟重新安排一次。

ConditionCheckingTask task = new ConditionCheckingTask( scheduledExecutorService ) ;

首先,安排该任务的运行,几乎没有延迟或没有延迟。

scheduledExecutorService.schedule( task , 0 , TimeUnit.MINUTES ) ;

作为第一次运行的一部分,任务将自行重新安排。


注意:在部署任何多线程代码之前,请务必仔细研究 Goetz 等人的优秀书籍 Java Concurrency在实践中

Sleeping main thread freezes your app

The entire point to multi-threading is to offload work from the initial thread running your app.

A thread sleeping until a certain time is not doing any other work. If the main thread of your app is the one asleep, then your app is entirely suspended and useless. If the thread running your GUI is the one asleep, then your app appears to be frozen to the user, apparently crashed, and effectively useless.

Also, as commented, threads as currently implemented in Java are relatively expensive in terms of memory and CPU. So we generally avoid having more than a few/several/dozens of threads running at a time. In the future, if Project Loom succeeds with its virtual threads, this situation may change radically.

You commented:

I think maybe I can do start time stop->monitor-> return-> sleep current thread-> monitor, quit monitor when condition met or time out?

That is effectively what a ScheduledExecutorService does. You define a task as a Runnable or Callable. The executor service runs your task periodically. In that task you can check for a condition on which you are waiting.

So no need for you to reinvent the wheel. Use the Executors framework built into Java; it’s excellent.

Search for that class name. Much has been already written on the subject, some of it authored by me. Search to learn more.

Regarding Timer, that class was supplanted years ago by the Executors framework. This fact is noted in the Javadoc.

Task reschedules itself

You clarified that your goal is to check a condition every minute for a maximum of ten times.

One way to do this is to have the task reschedule itself.

public class ConditionCheckingTask implements Runnable 
{
    private final ScheduledExecutorService ses ;
    private final Instant whenInstantiated = Instant.now() ;

    // Constructor
    public ConditionCheckingTask( final ScheduledExecutorService ses ) {
        this.ses = ses ;
    }

    @Override
    public void run() {
        if( someConditionIsTrue ) {
            doSomething ;
        } else if ( ChronoUnit.MINUTES.between( this.whenInstantiated , Instant.now() ) > 10 ) {
            // We have exceeded our time limit, so let this task die.
            return ;
        } else {  // Else wait a minute to check condition again.
            this.ses.schedule( this , 1 , TimeUnit.MINUTES ) ;
        }
    }
}

Make sure that accessing someConditionIsTrue is thread-safe. For example, if some other thread is flipping a boolean flag to signal our task, make that flag an AtomicBoolean. To learn more, search Stack Overflow, and read the book listed below.

Somewhere in your app, instantiate and remember a ScheduledExecutorService object.

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor() ;

Be sure to eventually shut down the executor service before your app exits. Search to learn more. This has been addressed many times on Stack Overflow.

Instantiate your task. Pass the scheduled executor service to the task’s constructor, so that it might reschedule itself every minute.

ConditionCheckingTask task = new ConditionCheckingTask( scheduledExecutorService ) ;

To start things off, schedule a run of that task with little or no delay.

scheduledExecutorService.schedule( task , 0 , TimeUnit.MINUTES ) ;

As part of the first run, the task will reschedule itself.


Note: Before deploying any multi-threaded code, be sure to study well the excellent book by Goetz et al., Java Concurrency In Practice.

秉烛思 2025-01-17 10:46:03

想知道为什么不在当前线程上实现定时任务
而不是创建一个新线程来处理这个问题?

您的“当前”线程可能是正在处理主请求的线程(例如,http 请求或任务/作业协调器)。其中之一的定时任务会将该线程与任何其他工作联系起来,直到任务完成。在基于 http 的服务上,这可能会导致 http 超时等。从最终用户体验和计算资源使用角度来看,这都不是一个好的设计。
通常,作为一种好的做法,您不会为该任务生成另一个新线程,而是使用线程池来有效利用资源。

Wondering why not just implement the timed task on the current thread
instead of creating a new thread to handle that?

Your "current" thread is perhaps the one which is processing the main request ( e.g., http request or a task/job coordinator). Timed task on one of these would tie this thread up for any other work until the task completes. On http based services this can leads to http timeouts etc. which is not a good design both in-terms of end user experience and the computing resource usage.
And generally as a good practice you do not spawn another new thread for the task, you rather use a thread pool for efficient resource utilization.

十二 2025-01-17 10:46:03

您不能在当前线程中执行此操作,因为您的主程序在它自己的线程中运行,并且您对其没有太多控制权。你最多可以让它进入睡眠状态。因此,您将在一个线程上启动主程序,该线程将派生另一个线程以按计划运行您的任务。

You cannot do it in the current thread because your main program runs in a thread of it's own and you don't have much control over it. You can at most put it on sleep. So, you'll start your main program on one thread which will spin off another thread to run your task on schedule.

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