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?
CodePudding user response:
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.
CodePudding user response:
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.
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.
CodePudding user response:
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.