I have an application which relies on Timer and scheduling, while its main method does nothing after performing the application setup.
I see this idiom used a lot:
public static void main(final String[] args) {
// schedule all tasks
while (true) {
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (final InterruptedException ignored) {
Thread.interrupted();
}
}
}
Is there a better way to write this? Do I really need this while loop for some reason? (It seems to have something to do with Thread.interrupted())
tl;dr
Do not manage threads yourself.
Use the Executors framework to create a pair of executor services.
One executor service can perform any requested tasks.
Another scheduled executor service can repeatedly check for incoming requests, indefinitely, resting for a specified amount of time between checks to free up CPU core. When a request is found, this executor service schedules a Runnable or Callable to be executed on the other executor service.
Executors framework
Is there a better way to put it?
Yes, there is a better way.
Use the Executors framework. See tutorial by Oracle.
This framework was invented so we would not have to manage threads directly. Most situations can be handled the Executors framework, with only rare cases requiring a programmer to juggle the threads.
And the Executors framework supplants the Timer & TimerTask classes. As noted in the Timer class Javadoc:
Java 5.0 introduced the java.util.concurrent package and one of the concurrency utilities therein is the ScheduledThreadPoolExecutor which is a thread pool for repeatedly executing tasks at a given rate or delay. It is effectively a more versatile replacement for the Timer/TimerTask combination, as it allows multiple service threads, accepts various time units, and doesn't require subclassing TimerTask (just implement Runnable). Configuring ScheduledThreadPoolExecutor with one thread makes it equivalent to Timer.
I assume that what you are trying to do is occasionally find a task needs to be done, and then perform that task on a background thread.
For that we need two executor services, each backed by a thread pool.
We need on executor service to perform the tasks which we discover over time need to be done. For this we use an unbounded thread pool via Executors.newCachedThreadPool. We call this our workers executor service. If you have CPU-intensive tasks, you may want an alternative executor service backed by a thread pool configured to a maximum number of threads.
We need a scheduled executor service that can be told to repeat one or more tasks every so often, on and on indefinitely. We have one task to assign here, the task that looks up what incoming requests have for other tasks to be scheduled on the other executor service. You do not explain in your Question, but I imagine you are checking a queue, or a database, or an email, or the presence of a file, for a list of new jobs to be run. That checking work is what you do here as a repeating task on this scheduled executor service. This executor service needs only a single thread in its pool, and is named dispatcher for lack of a better name.
Here is a version of the code simulating where we happen to find only one task needing to be done every time we check. We use a random number to simulate some arbitrary task being requested. To keep the code neat and tidy, we use the new switch expressions feature in Java 14. Each case in the switch generates a Runnable object, and submits that runnable object to the executor service. The executor service acts immediately to execute the run method on each runnable as it arrives upon submission. The part of the code generating the anonymous Runnable object is this lambda syntax:
( ) -> System.out.println( "Running Fruit report. Now: " + Instant.now() )
You could just as well use conventional syntax for generating the Runnable. You may well want to define separate classes that define Runnable in which you place your task code.
public class FruitReport implements Runnable
{
public void run() {
System.out.println( "Running Fruit report. Now: " + Instant.now() ) ;
}
}
Full example code.
package work.basil.example;
import java.time.Instant;
import java.util.concurrent.*;
public class TimerTaskManager
{
ExecutorService workers;
ScheduledExecutorService dispatcher;
private void launch ( )
{
System.out.println( "INFO - Method `launch` running at " + Instant.now() );
this.workers = Executors.newCachedThreadPool();
this.dispatcher = Executors.newSingleThreadScheduledExecutor();
this.dispatcher.scheduleWithFixedDelay(
( ) -> {
// Check for whatever input you have that prompts for tasks to be performed.
// We use a random number generator to simulate arbitrary work requests arriving.
// Using the new switch expressions feature in Java 14. https://openjdk.java.net/jeps/361
int r = ThreadLocalRandom.current().nextInt( 1 , 6 ); // inclusive-to-exclusive.
switch ( r )
{
case 1 -> this.workers.submit( ( ) -> System.out.println( "Running Fruit report. Now: " + Instant.now() ) ); // Passing an anonymous `Runnable` object to the `ExecutorService::submit` method.
case 2 -> this.workers.submit( ( ) -> System.out.println( "Running Wine report. Now: " + Instant.now() ) );
case 3 -> this.workers.submit( ( ) -> System.out.println( "Running Clothing report. Now: " + Instant.now() ) );
case 4 -> this.workers.submit( ( ) -> System.out.println( "Running Appliance report. Now: " + Instant.now() ) );
case 5 -> this.workers.submit( ( ) -> System.out.println( "Running Tools report. Now: " + Instant.now() ) );
default -> System.out.println( "ERROR - Unexpected r value: " + r );
}
} ,
3 ,
10 ,
TimeUnit.SECONDS
);
}
private void shutdown ( )
{
this.dispatcher.shutdown();
this.workers.shutdown();
System.out.println( "INFO - Method `shutdown` running at " + Instant.now() );
}
public static void main ( String[] args )
{
TimerTaskManager app = new TimerTaskManager();
app.launch();
try
{
Thread.sleep( TimeUnit.MINUTES.toMillis( 1 ) );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
app.shutdown();
}
}
}
When run.
INFO - Method `launch` running at 2020-06-28T04:16:17.742443Z
Running Wine report. Now: 2020-06-28T04:16:20.786653Z
Running Tools report. Now: 2020-06-28T04:16:30.787891Z
Running Appliance report. Now: 2020-06-28T04:16:40.791585Z
Running Wine report. Now: 2020-06-28T04:16:50.796355Z
Running Fruit report. Now: 2020-06-28T04:17:00.800407Z
Running Appliance report. Now: 2020-06-28T04:17:10.805166Z
INFO - Method `shutdown` running at 2020-06-28T04:17:17.783938Z
Let's complicate that a bit, to better simulate your likely real-world case where some arbitrary number of requests are found to be pending every time your scheduled executor service checks. To simulate this, we randomly repeat the switch statement.
package work.basil.example;
import java.time.Instant;
import java.util.concurrent.*;
public class TimerTaskManager
{
ExecutorService workers;
ScheduledExecutorService dispatcher;
private void launch ( )
{
System.out.println( "INFO - Method `launch` running at " + Instant.now() );
this.workers = Executors.newCachedThreadPool();
this.dispatcher = Executors.newSingleThreadScheduledExecutor();
this.dispatcher.scheduleWithFixedDelay(
( ) -> {
// Check for whatever input you have that prompts for tasks to be performed.
int countRequests = ThreadLocalRandom.current().nextInt( 1 , 7 );
System.out.println( "INFO - Found " + countRequests + " incoming requests for work to be done. Now: " + Instant.now() );
for ( int i = 1 ; i <= countRequests ; i++ )
{
// We use a random number generator to simulate arbitrary work requests arriving.
// Using the new switch expressions feature in Java 14. https://openjdk.java.net/jeps/361
int r = ThreadLocalRandom.current().nextInt( 1 , 6 ); // inclusive-to-exclusive.
switch ( r )
{
case 1 -> this.workers.submit( ( ) -> System.out.println( "Running Fruit report. Now: " + Instant.now() ) ); // Passing an anonymous `Runnable` object to the `ExecutorService::submit` method.
case 2 -> this.workers.submit( ( ) -> System.out.println( "Running Wine report. Now: " + Instant.now() ) );
case 3 -> this.workers.submit( ( ) -> System.out.println( "Running Clothing report. Now: " + Instant.now() ) );
case 4 -> this.workers.submit( ( ) -> System.out.println( "Running Appliance report. Now: " + Instant.now() ) );
case 5 -> this.workers.submit( ( ) -> System.out.println( "Running Tools report. Now: " + Instant.now() ) );
default -> System.out.println( "ERROR - Unexpected r value: " + r );
}
}
} ,
3 ,
10 ,
TimeUnit.SECONDS
);
}
private void shutdown ( )
{
this.dispatcher.shutdown();
this.workers.shutdown();
System.out.println( "INFO - Method `shutdown` running at " + Instant.now() );
}
public static void main ( String[] args )
{
TimerTaskManager app = new TimerTaskManager();
app.launch();
try
{
Thread.sleep( TimeUnit.MINUTES.toMillis( 1 ) );
}
catch ( InterruptedException e )
{
e.printStackTrace();
}
finally
{
app.shutdown();
}
}
}
When run.
INFO - Method `launch` running at 2020-06-28T04:34:52.097616Z
INFO - Found 2 incoming requests for work to be done. Now: 2020-06-28T04:34:55.112823Z
Running Tools report. Now: 2020-06-28T04:34:55.122258Z
Running Appliance report. Now: 2020-06-28T04:34:55.122653Z
INFO - Found 2 incoming requests for work to be done. Now: 2020-06-28T04:35:05.127456Z
Running Appliance report. Now: 2020-06-28T04:35:05.128309Z
Running Clothing report. Now: 2020-06-28T04:35:05.128297Z
INFO - Found 5 incoming requests for work to be done. Now: 2020-06-28T04:35:15.128481Z
Running Tools report. Now: 2020-06-28T04:35:15.129414Z
Running Wine report. Now: 2020-06-28T04:35:15.129430Z
Running Appliance report. Now: 2020-06-28T04:35:15.129663Z
Running Tools report. Now: 2020-06-28T04:35:15.130001Z
Running Fruit report. Now: 2020-06-28T04:35:15.130441Z
INFO - Found 4 incoming requests for work to be done. Now: 2020-06-28T04:35:25.133727Z
Running Clothing report. Now: 2020-06-28T04:35:25.133880Z
Running Wine report. Now: 2020-06-28T04:35:25.133917Z
Running Wine report. Now: 2020-06-28T04:35:25.133967Z
Running Wine report. Now: 2020-06-28T04:35:25.134148Z
INFO - Found 6 incoming requests for work to be done. Now: 2020-06-28T04:35:35.136503Z
Running Tools report. Now: 2020-06-28T04:35:35.136663Z
Running Wine report. Now: 2020-06-28T04:35:35.136733Z
Running Clothing report. Now: 2020-06-28T04:35:35.136764Z
Running Clothing report. Now: 2020-06-28T04:35:35.136735Z
Running Appliance report. Now: 2020-06-28T04:35:35.137363Z
Running Clothing report. Now: 2020-06-28T04:35:35.137349Z
INFO - Found 3 incoming requests for work to be done. Now: 2020-06-28T04:35:45.136728Z
Running Appliance report. Now: 2020-06-28T04:35:45.136943Z
Running Clothing report. Now: 2020-06-28T04:35:45.136940Z
Running Tools report. Now: 2020-06-28T04:35:45.136948Z
INFO - Method `shutdown` running at 2020-06-28T04:35:52.111007Z
Caution: Be sure to gracefully shutdown each of your executor services when no longer needed or when your app is exiting. Otherwise their backing thread pool may continue to live indefinitely, zombie-like.
Caution: Wrap your code submitted to a scheduled executor service in a try-catch for any unexpected exceptions and possibly errors. If a throwable bubbles up to reach the scheduled executor service, that service silently stops scheduling any more work. Search Stack Overflow to learn more.
Thread.currentThread().join();
Will sleep until the JVM is killed.
See Use of Thread.currentThread().join() in Java for an explanation.
Related
I'm trying to make a ScheduledExecutorService where only one task is active at a time and only once a task has finished, the next task will begin its delay with an arbitrary delay amount.
As a very simple example of what I mean, take a look at this method. The idea is to schedule 10 Runnables to simulate a countdown from 10-1. Each interval takes one second (imagine this was an arbitrary amount of seconds though, I can't use scheduleAtFixedRate in my use case).
private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
public void startCountdown() {
for (int i = 10; i > 0; i--) {
int countdownNumber = i;
scheduler.schedule(() -> {
System.out.println(countdownNumber);
}, 1, TimeUnit.SECONDS);
}
}
However, this will simply print all 10 numbers at once, instead of waiting for a second between each value. The only way I can circumvent this (to my knowledge) is calculating the ABSOLUTE delay, as opposed to the relative one.
While it's possible to calculate the absolute time for each item, it would be quite a hassle. Isn't there some construct in Java that allows me to queue many items at once, but waits in between each item for the delay to finish, rather than processing every delay at once?
tl;dr
Do not use your countdown number to directly schedule your tasks. Have one number for scheduling number of seconds to wait (1,2,3,…) and another number for the countdown (9,8,7,…).
Use scheduleAtFixedRate to schedule your tasks for an increasing number of seconds. No need for executor service to be single-threaded.
Details
Task that re-schedules itself
Isn't there some construct in Java that allows me to queue many items at once, but waits in between each item for the delay to finish, rather than processing every delay at once?
If you have an arbitrary amount of time not known up front when beginning the scheduling, then you should only run one task at a time. Let the task re-schedule itself.
To enable a task to re-schedule itself, pass a reference to the ScheduledExecutorService to the task object (your Runnable or Callable) as an argument in the constructor. After the task completes its main work, it discovers/calculates the amount of time to elapse for the next run. The task then submits itself (this) to the passed executor service, along with the amount of time to elapse before the next task execution.
I have already posted Answers on Stack Overflow with code for tasks that re-schedule themselves. I would expect others have as well. Search to learn more.
Regarding the "countdown" aspect of your Question, read on.
Countdown
You have the right approach in using a scheduled executor service. The problem is that you are calling the wrong method on that class.
Your call to schedule means you are scheduling several tasks to all run after a single second. All those tasks are starting from the moment your call is made. So each runs after one second from your call to schedule. So the ten tasks are all waiting a second from almost the same moment: ten moments a split-second apart, the split-second being the time it takes for your for loop to continue.
scheduleAtFixedRate
The method you are looking for is scheduleAtFixedRate. To quote the doc:
Submits a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is, executions will commence after initialDelay, then initialDelay + period, then initialDelay + 2 * period, and so on.
private ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
public void countdown( ScheduledExecutorService scheduler )
{
for ( int i = 1 ; i <= 10 ; i++ )
{
int countdownNumber = 10 - i ; // For 9 through 0. Add 1 for 10 through 1.
scheduler.scheduleAtFixedRate
(
() -> { System.out.println( countdownNumber ) ; } ,
i , // 1 second, then 2 seconds, then 3 seconds, and so on to 10 seconds.
TimeUnit.SECONDS
) ;
}
}
… Eventually shut down your scheduled executor service.
Notice how this approach does not require the ScheduledExecutorService to be single-threaded.
Full example
Here is a complete example app.
package work.basil.example.countdown;
import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Countdown
{
public static void main ( String[] args )
{
Countdown app = new Countdown();
app.demo();
}
private void demo ( )
{
System.out.println( "INFO - Demo start. " + Instant.now() );
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); // Our code does *not* require the executor service to be single-threaded. But for this particular example, we might as well do it that way.
this.countdown( scheduler );
this.shutdownAndAwaitTermination( scheduler , Duration.ofMinutes( 1 ) , Duration.ofMinutes( 1 ) );
System.out.println( "INFO - Demo end. " + Instant.now() );
}
public void countdown ( final ScheduledExecutorService scheduler )
{
Objects.requireNonNull( scheduler ) ;
for ( int i = 1 ; i <= 10 ; i++ )
{
int countdownNumber = 10 - i; // For 9 through 0. Add 1 for 10 through 1.
scheduler.scheduleAtFixedRate
(
( ) -> { System.out.println( "Countdown: " + countdownNumber + " at " + Instant.now() ); } ,
i , // 1 second, then 2 seconds, then 3 seconds, and so on to 10 seconds.
TimeUnit.SECONDS
);
}
}
// My slightly modified version of boilerplate code taken from Javadoc of `ExecutorService`.
// https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ExecutorService.html
void shutdownAndAwaitTermination ( final ExecutorService executorService , final Duration waitForWork , final Duration waitForRemainingTasks )
{
Objects.requireNonNull( executorService ) ;
Objects.requireNonNull( waitForWork ) ;
Objects.requireNonNull( waitForRemainingTasks ) ;
executorService.shutdown(); // Disable new tasks from being submitted
try
{
// Wait a while for existing tasks to terminate
if ( ! executorService.awaitTermination( waitForWork.toMillis() , TimeUnit.MILLISECONDS ) )
{
executorService.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if ( ! executorService.awaitTermination( waitForRemainingTasks.toMillis() , TimeUnit.MILLISECONDS ) )
{ System.err.println( "ExecutorService did not terminate." ); }
}
}
catch ( InterruptedException ex )
{
// (Re-)Cancel if current thread also interrupted
executorService.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
System.out.println( "DEBUG - shutdownAndAwaitTermination ran. " + Instant.now() );
}
}
When run:
INFO - Demo start. 2023-01-20T21:24:47.379244Z
Countdown: 9 at 2023-01-20T21:24:48.390269Z
Countdown: 8 at 2023-01-20T21:24:49.390045Z
Countdown: 7 at 2023-01-20T21:24:50.389957Z
Countdown: 6 at 2023-01-20T21:24:51.386468Z
Countdown: 5 at 2023-01-20T21:24:52.390168Z
Countdown: 4 at 2023-01-20T21:24:53.386538Z
Countdown: 3 at 2023-01-20T21:24:54.387583Z
Countdown: 2 at 2023-01-20T21:24:55.386705Z
Countdown: 1 at 2023-01-20T21:24:56.389490Z
Countdown: 0 at 2023-01-20T21:24:57.387566Z
DEBUG - shutdownAndAwaitTermination ran. 2023-01-20T21:24:57.391224Z
INFO - Demo end. 2023-01-20T21:24:57.391966Z
By the way, know that scheduled tasks do not always fire exactly on time for a variety of reasons.
Also, be aware that messages sent to System.out across threads do not always appear on the console chronologically. If you care about order, always include and study a timestamp such as Instant#now.
You can schedule the next call inside the task.
void countdown(final int i) {
scheduler.schedule(() -> {
System.out.println(i);
if (i > 0) countdown(i - 1);
}, 1, TimeUnit.SECONDS);
}
// ...
countdown(10);
How can I simulate or write a code that would indicate that Java blocks a function till it has finished its execution.
This way I will be able to show that Java has blocking I/O.
What I thought as my initial solution was to make an infinite loop but that didn't work as it will never finish its execution.
my other solution was to make a REST API and in that get request would delay and return something and think this might work but is there a native way to do it?
Here is the Java code below I want to delay the method fun2() without creating a new thread.
public class SetTimeOut {
public static void fun1(String str){
System.out.println(str);
}
public static void fun2(String str){
//how to make this function wait for 3 sec?
System.out.println(str);
}
public static void fun3(String str){
System.out.println(str);
}
public static void main(String[] args) {
fun1("Hello from fun1 is being called");
fun2("Hello from fun2 is being called");
fun3("Hello from fun3 is being called");
}
}
Here is an equivalent JavaScript code to show that JavaScript has a non-blocking I/O. Want to simulate a similar kind of behavior in Java.
console.log("Hey");
setTimeout(() => {
console.log("there!")
},3000);
console.log("please help");
just want to write something similar in java but it should block till the execution of the setTimeout() function is complete.
tl;dr
You can pause execution of a thread.
Thread
.sleep(
Duration.ofSeconds ( 7 )
)
Sleep
As discussed in comments, you can sleep the thread for a specific length of time. The static method Thread.sleep method pauses execution of the current thread.
See Pausing Execution with Sleep in The Java Tutorials by Oracle Corp.
Thread.sleep( Duration.of… ( … ) ) ;
For example, sleep a half second.
Thread.sleep( Duration.ofMillis ( 500 ) ) ; // A half-second.
Or seven seconds.
Thread.sleep( Duration.ofSeconds ( 7 ) ) ; // Seven seconds.
Or half a day.
Thread.sleep( Duration.ofHours ( 12 ) ) ; // Twelve hours.
Prior to Java 19
Before Java 19+, you must pass a mere int rather than a Duration, as a count of milliseconds.
For example, here we pause for a half-second.
Thread.sleep( 500 ) ; // 500 milliseconds is a half-second.
In Java 8 through Java 18, no need for you to do the math to get milliseconds. Use Duration#toMillis.
Thread.sleep( Duration.ofMinutes( 1 ).plusSeconds( 30 ).toMillis() ) ; // 1.5 minutes as a count of milliseconds.
Let's say I have a task that will check if a certain condition has been met. If that condition has been met, I should terminate the task early. However, I should continue to run the task for N number of minutes while continuously checking if that condition has been met. At the end of N minutes, the task should terminate itself.
I've been looking into Timer, TimerTask, and ExecutorService, but none of them seem to offer the type of solution I am looking for. For example, these approaches will allow you to schedule a task to run once, or repeatedly, but not for a specific amount of time (aka N minutes).
ScheduledExecutorService can accomplish this.
What you need to do:
Schedule the block of work you want to do at a fixed interval (in time units, so like seconds, minutes, hours, etc)
When you've completed the work, execute ScheduledExecutorService#shutdownNow
To time out after a period of time, use ScheduledExecutorService#awaitTermination to delay the termination of the scheduled task until your threshold elapses
Task reschedules itself
The Answer by Makato is right about suggesting the use of an executor service. But ending the scheduled executor service as the way to end your repeating task is less than optimal. Often we have one executor service handling many tasks. So while we want our repeating task to end, the executor service may need to continue scheduling other tasks to run.
Instead, ironically, 👉🏻 do not schedule the repeating task to repeat. Schedule the task to run once. Have the task check its status.
If the status requires the task run again, have the task schedule itself on the executor service for another run.
If the status is complete, and no further executions of that task are needed, simply opt out of another submission to the executor service.
The key to making this work is passing a reference to the scheduled executor service to the constructor of your task. The task keeps that reference as a member field of its own class. So the task can use that reference to pass itself to the scheduled executor service for another submission. The task becomes self-scheduling.
Here is the source code for an example of such a task.
Notice that in addition to passing a reference to the scheduled executor service, we also pass an Instant representing our target moment when we want to stop our repeating task. And we pass a Duration object for the amount of time to wait between executions of this task.
Examine that run method. The task compares the current moment against the target moment. If not yet passed, the task schedules it own next execution. If passed, no rescheduling, mission accomplished.
package work.basil.example.concurrency;
import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ExpiringTask implements Runnable
{
private final Instant timeLimit;
private final Duration untilNextRun;
private final ScheduledExecutorService scheduledExecutorService;
public ExpiringTask ( final Instant timeLimit , final Duration untilNextRun , final ScheduledExecutorService scheduledExecutorService )
{
this.timeLimit = Objects.requireNonNull( timeLimit );
this.untilNextRun = Objects.requireNonNull( untilNextRun );
this.scheduledExecutorService = Objects.requireNonNull( scheduledExecutorService );
}
#Override
public void run ( )
{
System.out.println( "INFO - Running the `run` method of our ExpiringTask. Now: " + Instant.now() );
if ( Instant.now().isAfter( this.timeLimit ) )
{
System.out.println( "☑️ Mission accomplished. Our task has expired. Now: " + Instant.now() );
}
else
{
System.out.println( "⏲️ Not yet expired. Reschedule to check again. Now: " + Instant.now() );
this.scheduledExecutorService.schedule( this , this.untilNextRun.toNanos() , TimeUnit.NANOSECONDS );
}
}
}
In real work, when rescheduling the task, I would check that the executor service is still available. To do so, make a call to ExecutorSerivce#isShutdown. This step is omitted in code above for brevity and simplicity.
How to run get that task running? Here is the main chunk of an app to demonstrate this task running repeatedly while rescheduling itself.
First we establish our target time limit as five seconds from now. Then we specify waiting between runs for one second each time. And we get a scheduled executor service. Be sure to keep that reference around, as you must be careful to gracefully shut down the executor service eventually — otherwise its backing thread pool may continue running indefinitely, like a zombie 🧟♂️.
Next step is to instantiate our task, passing the pieces to its constructor. Finally, to get things working, we tell the scheduled executor service to run our task after a certain amount of delay. For this first run we want to run immediately, so we specify a delay of zero nanoseconds.
Instant timeLimit = Instant.now().plus( Duration.ofSeconds( 5 ) );
Duration untilNextRun = Duration.ofSeconds( 1 );
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ExpiringTask task = new ExpiringTask( timeLimit , untilNextRun , ses );
ses.schedule( task , 0 , TimeUnit.NANOSECONDS );
That covers the main idea. Here is the complete app class containing that code excerpted directly above.
package work.basil.example.concurrency;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class KeepRunningUntil
{
public static void main ( String[] args )
{
KeepRunningUntil app = new KeepRunningUntil();
app.demo();
System.out.println( "INFO - Demo ending. Now: " + Instant.now() );
}
private void demo ( )
{
System.out.println( "INFO - 'demo' method starting. " + Instant.now() );
Instant timeLimit = Instant.now().plus( Duration.ofSeconds( 5 ) );
Duration untilNextRun = Duration.ofSeconds( 1 );
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ExpiringTask task = new ExpiringTask( timeLimit , untilNextRun , ses );
ses.schedule( task , 0 , TimeUnit.NANOSECONDS );
// Wait a while for our background task to do its thing.
try { Thread.sleep( Duration.ofSeconds( 10 ).toMillis() ); } catch ( InterruptedException e ) { throw new RuntimeException( e ); }
this.shutdownAndAwaitTermination( ses );
System.out.println( "INFO - 'demo' method ending. " + Instant.now() );
}
private void shutdownAndAwaitTermination ( ExecutorService executorService )
{
// Boilerplate taken from Javadoc.
// https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/concurrent/ExecutorService.html#isShutdown()
executorService.shutdown(); // Disable new tasks from being submitted
try
{
// Wait a while for existing tasks to terminate
if ( ! executorService.awaitTermination( 60 , TimeUnit.SECONDS ) )
{
executorService.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if ( ! executorService.awaitTermination( 60 , TimeUnit.SECONDS ) )
{ System.err.println( "Pool did not terminate" ); }
}
}
catch ( InterruptedException ex )
{
// (Re-)Cancel if current thread also interrupted
executorService.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
}
When run.
INFO - 'demo' method starting. 2022-08-25T08:16:28.384638Z
INFO - Running the `run` method of our ExpiringTask. Now: 2022-08-25T08:16:28.402471Z
⏲️ Not yet expired. Reschedule to check again. Now: 2022-08-25T08:16:28.402657Z
INFO - Running the `run` method of our ExpiringTask. Now: 2022-08-25T08:16:29.408010Z
⏲️ Not yet expired. Reschedule to check again. Now: 2022-08-25T08:16:29.408126Z
INFO - Running the `run` method of our ExpiringTask. Now: 2022-08-25T08:16:30.413336Z
⏲️ Not yet expired. Reschedule to check again. Now: 2022-08-25T08:16:30.413599Z
INFO - Running the `run` method of our ExpiringTask. Now: 2022-08-25T08:16:31.416144Z
⏲️ Not yet expired. Reschedule to check again. Now: 2022-08-25T08:16:31.416230Z
INFO - Running the `run` method of our ExpiringTask. Now: 2022-08-25T08:16:32.421484Z
⏲️ Not yet expired. Reschedule to check again. Now: 2022-08-25T08:16:32.421873Z
INFO - Running the `run` method of our ExpiringTask. Now: 2022-08-25T08:16:33.425519Z
☑️ Mission accomplished. Our task has expired. Now: 2022-08-25T08:16:33.425863Z
INFO - 'demo' method ending. 2022-08-25T08:16:38.407566Z
INFO - Demo ending. Now: 2022-08-25T08:16:38.407755Z
The other answers mentioned here are good. Just giving another idea that might be simpler.
Schedule your task to run periodically and don't worry about termination
Create a class Lets call it TaskManager and make one of its members an ExecutorService. Pass the ExecutorService that you use for your task sceduling to your TaskManager. Also in your task manager add a counter that your task will increment each time that it runs. Obviously your TaskManager should have a static method incrementCounter() that your task will use. Also your TaskManager should have a method static method teminateTask().
So now when the counter reaches your limit TaskManager will call method shutDown() of your ExecutorService. Or if your task in your internal logic comes to conclusion that its time to terminate it will call method teminateTask() of your TaskManager
My expected output is
Count : 1
Count : 2
Count : 3
Count : 4
Count : 5
I have tried synchronized and Lock but neither of them works. I reach to
Ending Main
sooner than I finish the loop completely. Current output is:
Starting Main
Count : 1
Count : 2
Count : 3
Count : 4
Ending Main
Count : 5
Any Idea why Count : 5 is after Ending Main? Here is my code:
public class Demo {
public static void main( String [] args ) {
System.out.println( "Starting Main" ) ;
for ( int i = 1 ; i <= 5 ; i++ ) {
Thread numberThread = new Thread(new NumberTask(i)) ;
numberThread.start() ;
}
System.out.println( "Ending Main" ) ;
}
}
class NumberTask implements Runnable {
private Lock bankLock = new ReentrantLock();
int count ;
public NumberTask( int count ) {
this.count = count ;
}
synchronized public void run() {
bankLock.lock();
try {
System.out.println( "Count : " + count ) ;
} finally {
bankLock.unlock();
}
}
}
Any Idea why "Count : 5" is after "Ending Main"?
When a thread is started, there is no guarantee that it starts running immediately. It is normal for the thread that forked the new thread to continue to run as the new thread initializes. So, after the main thread starts the 5th thread, it continues to run and beats the thread to the System.out.println("Ending Main"); statement.
It is important to realize that the whole point of threads is that they run in an asynchronous manner. Because the threads can be scheduled on separate CPUs/cores running concurrently, it is often very hard to predict the order of operations in a thread program. For example. it is also possible that you might see "Count 2" printed before "Count 1" just because of thread race conditions. I just ran it starting 500 threads and I saw:
Count : 128
Count : 130
Count : 129
Count : 131
Also, because your bankLock is local to your NumberTask class, it will not lock between threads. You could make the lock static to NumberTask to have there be one lock per-class or you could instantiate the lock in main and pass it into the NumberTask constructor. You really don't need the lock here since the System.out is a PrintStram which is a synchronized object. The same goes for the synchronized run() method. Since you will be synchronizing on the NumberTask instance, it doesn't do anything because no other thread will be synchronizing on the same object.
You can use join() to wait for other thread to finish. Your code need to be updated as follows:
public static void main( String [] args ) {
System.out.println( "Starting Main" ) ;
Thread numberThread;
for ( int i = 1 ; i <= 5 ; i++ ) {
numberThread = new Thread(new NumberTask(i)) ;
numberThread.start() ;
}
numberThread.join();
System.out.println( "Ending Main" ) ;
}
Execution of threads is not predictable, so you get this behavior. Use join() method to make one thread's execution to the end of another thread's execution.
Kindly read Java thread unpredictable
How should I test my algorithm in terms of speed? The enhanced algorithm I made and the original algorithm search the same depth and they both give the same move, they only differ in terms of speed.
Do you know how I should test my new algorithm that I made? Aside from just subtracting the system time it started to system time it ended. What I'm trying to say is I need to do a little formal tests with little bit of formulas. Should I simulate all possible moves and tally the time each algorithm (enhanced and original) took time to decide on a move? I'm quite clueless here.
I've used the below method a few times and have had success. If you are interested in multi-threaded benchmarking refer to the link at the bottom of the page.
Timing a single-threaded task using CPU, system, and user time
Timing a single-threaded task using CPU, system, and user time
"User time" is the time spent running your application's own code.
"System time" is the time spent running OS code on behalf of your
application (such as for I/O).
Java 1.5 introduced the java.lang.management package to monitor the JVM. The entry point for the package is the ManagementFactory class. It's static methods return a variety of different "MXBean" objects that report JVM information. One such bean can report thread CPU and user time.
Call ManagementFactory . getThreadMXBean() to get a ThreadMXBean that describes current JVM threads. The bean's getCurrentThreadCpuTime() method returns the CPU time for the current thread. The getCurrentThreadUserTime() method returns the thread's user time. Both of these report times in nanoseconds (but see Appendix on Times and (lack of) nanosecond accuracy).
Be sure to call isCurrentThreadCpuTimeSupported() first, though. If it returns false (rare), the JVM implementation or OS does not support getting CPU or user times. In that case, you're back to using wall clock time.
import java.lang.management.*;
/** Get CPU time in nanoseconds. */
public long getCpuTime( ) {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
bean.getCurrentThreadCpuTime( ) : 0L;
}
/** Get user time in nanoseconds. */
public long getUserTime( ) {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
bean.getCurrentThreadUserTime( ) : 0L;
}
/** Get system time in nanoseconds. */
public long getSystemTime( ) {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
(bean.getCurrentCpuTime( ) - bean.getCurrentThreadUserTime( )) : 0L;
}
These methods return the CPU, user, and system time since the thread started. To time a task after the thread has started, call one or more of these before and after the task and take the difference:
long startSystemTimeNano = getSystemTime( );
long startUserTimeNano = getUserTime( );
... do task ...
long taskUserTimeNano = getUserTime( ) - startUserTimeNano;
long taskSystemTimeNano = getSystemTime( ) - startSystemTimeNano;
Taken from, http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking#TimingasinglethreadedtaskusingCPUsystemandusertime
Here is a sample program to capture timings, you can change this to suit your needs:
package com.quicklyjava;
public class Main {
/**
* #param args
* #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// start time
long time = System.nanoTime();
for (int i = 0; i < 5; i++) {
System.out.println("Sleeping Zzzz... " + i);
Thread.sleep(1000);
}
long difference = System.nanoTime() - time;
System.out.println("It took " + difference + " nano seconds to finish");
}
}
And here is the output:
Sleeping Zzzz... 0
Sleeping Zzzz... 1
Sleeping Zzzz... 2
Sleeping Zzzz... 3
Sleeping Zzzz... 4
It took 5007507169 nano seconds to finish